Skip to content

Commit

Permalink
Allow disconnected parts in graph
Browse files Browse the repository at this point in the history
  • Loading branch information
jorenvo committed Aug 27, 2021
1 parent 4a9a6d4 commit b7c2c21
Showing 1 changed file with 36 additions and 27 deletions.
63 changes: 36 additions & 27 deletions prettymaps/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,46 @@

from functools import reduce


# Compute circular or square boundary given point, radius and crs
def get_boundary(point, radius, crs, circle = True, dilate = 0):
def get_boundary(point, radius, crs, circle=True, dilate=0):
if circle:
return ox.project_gdf(
GeoDataFrame(geometry = [Point(point[::-1])], crs = crs)
GeoDataFrame(geometry=[Point(point[::-1])], crs=crs)
).geometry[0].buffer(radius)
else:
x, y = np.stack(ox.project_gdf(
GeoDataFrame(geometry = [Point(point[::-1])], crs = crs)
GeoDataFrame(geometry=[Point(point[::-1])], crs=crs)
).geometry[0].xy)
r = radius
return Polygon([
(x-r, y-r), (x+r, y-r), (x+r, y+r), (x-r, y+r)
(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)
]).buffer(dilate)


# Get perimeter
def get_perimeter(query, by_osmid = False, **kwargs):
return ox.geocode_to_gdf(query, by_osmid = by_osmid, **kwargs, **{x: kwargs[x] for x in ['circle', 'dilate'] if x in kwargs.keys()})
def get_perimeter(query, by_osmid=False, **kwargs):
return ox.geocode_to_gdf(query, by_osmid=by_osmid, **kwargs,
**{x: kwargs[x] for x in ['circle', 'dilate'] if x in kwargs.keys()})

# Get geometries
def get_geometries(perimeter = None, point = None, radius = None, tags = {}, perimeter_tolerance = 0, union = True, circle = True, dilate = 0):

# Get geometries
def get_geometries(perimeter=None, point=None, radius=None, tags={}, perimeter_tolerance=0, union=True, circle=True,
dilate=0):
if perimeter is not None:
# Boundary defined by polygon (perimeter)
geometries = ox.geometries_from_polygon(
unary_union(perimeter.geometry).buffer(perimeter_tolerance) if perimeter_tolerance > 0 else unary_union(perimeter.geometry),
tags = {tags: True} if type(tags) == str else tags
unary_union(perimeter.geometry).buffer(perimeter_tolerance) if perimeter_tolerance > 0 else unary_union(
perimeter.geometry),
tags={tags: True} if type(tags) == str else tags
)
perimeter = unary_union(ox.project_gdf(perimeter).geometry)

elif (point is not None) and (radius is not None):
# Boundary defined by circle with radius 'radius' around point
geometries = ox.geometries_from_point(point, dist = radius+dilate, tags = {tags: True} if type(tags) == str else tags)
perimeter = get_boundary(point, radius, geometries.crs, circle = circle, dilate = dilate)
geometries = ox.geometries_from_point(point, dist=radius + dilate,
tags={tags: True} if type(tags) == str else tags)
perimeter = get_boundary(point, radius, geometries.crs, circle=circle, dilate=dilate)

# Project GDF
if len(geometries) > 0:
Expand All @@ -67,40 +73,41 @@ def get_geometries(perimeter = None, point = None, radius = None, tags = {}, per
geometries = geometries.intersection(perimeter)

if union:
geometries = unary_union(reduce(lambda x,y: x+y, [
geometries = unary_union(reduce(lambda x, y: x + y, [
[x] if type(x) == Polygon else list(x)
for x in geometries if type(x) in [Polygon, MultiPolygon]
], []))
else:
geometries = MultiPolygon(reduce(lambda x,y: x+y, [
geometries = MultiPolygon(reduce(lambda x, y: x + y, [
[x] if type(x) == Polygon else list(x)
for x in geometries if type(x) in [Polygon, MultiPolygon]
], []))

return geometries

# Get streets
def get_streets(perimeter = None, point = None, radius = None, layer = 'streets', width = 6, custom_filter = None, circle = True, dilate = 0):

# Get streets
def get_streets(perimeter=None, point=None, radius=None, layer='streets', width=6, custom_filter=None, circle=True,
dilate=0):
if layer == 'streets':
layer = 'highway'

# Boundary defined by polygon (perimeter)
if perimeter is not None:
# Fetch streets data, project & convert to GDF
streets = ox.graph_from_polygon(unary_union(perimeter.geometry), custom_filter = custom_filter)
streets = ox.graph_from_polygon(unary_union(perimeter.geometry), custom_filter=custom_filter, retain_all=True)
streets = ox.project_graph(streets)
streets = ox.graph_to_gdfs(streets, nodes = False)
streets = ox.graph_to_gdfs(streets, nodes=False)
# Boundary defined by polygon (perimeter)
elif (point is not None) and (radius is not None):
# Fetch streets data, save CRS & project
streets = ox.graph_from_point(point, dist = radius+dilate, custom_filter = custom_filter)
crs = ox.graph_to_gdfs(streets, nodes = False).crs
streets = ox.graph_from_point(point, dist=radius + dilate, custom_filter=custom_filter, retain_all=True)
crs = ox.graph_to_gdfs(streets, nodes=False).crs
streets = ox.project_graph(streets)
# Compute perimeter from point & CRS
perimeter = get_boundary(point, radius, crs, circle = circle, dilate = dilate)
perimeter = get_boundary(point, radius, crs, circle=circle, dilate=dilate)
# Convert to GDF
streets = ox.graph_to_gdfs(streets, nodes = False)
streets = ox.graph_to_gdfs(streets, nodes=False)
# Intersect with perimeter & filter empty elements
streets.geometry = streets.geometry.intersection(perimeter)
streets = streets[~streets.geometry.is_empty]
Expand All @@ -110,9 +117,10 @@ def get_streets(perimeter = None, point = None, radius = None, layer = 'streets'
# Dilate streets of each highway type == 'highway' using width 'w'
MultiLineString(
streets[(streets[layer] == highway) & (streets.geometry.type == 'LineString')].geometry.tolist() +
list(reduce(lambda x, y: x+y, [
list(reduce(lambda x, y: x + y, [
list(lines)
for lines in streets[(streets[layer] == highway) & (streets.geometry.type == 'MultiLineString')].geometry
for lines in
streets[(streets[layer] == highway) & (streets.geometry.type == 'MultiLineString')].geometry
], []))
).buffer(w)
for highway, w in width.items()
Expand All @@ -123,6 +131,7 @@ def get_streets(perimeter = None, point = None, radius = None, layer = 'streets'

return streets


# Get any layer
def get_layer(layer, **kwargs):
# Fetch perimeter
Expand All @@ -133,7 +142,7 @@ def get_layer(layer, **kwargs):
# If point and radius are provided:
elif 'point' in kwargs and 'radius' in kwargs:
# Dummy request to fetch CRS
crs = ox.graph_to_gdfs(ox.graph_from_point(kwargs['point'], dist = kwargs['radius']), nodes = False).crs
crs = ox.graph_to_gdfs(ox.graph_from_point(kwargs['point'], dist=kwargs['radius']), nodes=False).crs
perimeter = get_boundary(
kwargs['point'], kwargs['radius'], crs,
**{x: kwargs[x] for x in ['circle', 'dilate'] if x in kwargs.keys()}
Expand All @@ -143,7 +152,7 @@ def get_layer(layer, **kwargs):
raise Exception("Either 'perimeter' or 'point' & 'radius' must be provided")
# Fetch streets or railway
if layer in ['streets', 'railway', 'waterway']:
return get_streets(**kwargs, layer = layer)
return get_streets(**kwargs, layer=layer)
# Fetch geometries
else:
return get_geometries(**kwargs)
return get_geometries(**kwargs)

0 comments on commit b7c2c21

Please sign in to comment.