Source code for measprocess.geospatial
import overpy
import geopandas as gpd
from shapely.geometry import LineString, Polygon
from scipy.spatial.distance import cdist
import numpy as np
import warnings
import time
[docs]def make_overpy_request(request_body, retries):
for _ in range(retries):
try:
api = overpy.Overpass()
result = api.query(
request_body
)
except (overpy.exception.OverpassTooManyRequests, overpy.exception.OverpassGatewayTimeout):
warnings.warn("Overpass Too Many Requests --- Retry in 5 seconds")
time.sleep(5)
else:
return result
[docs]def get_geoseries_streets(measurement_coords, retries=5):
'''
Obtain the street shapes in the area spanned by the measurement_coords.
:param measurement_coords: A geopandas geoseries of Points(lon, lat) representing the measurement positions in a EPSG:4326 projection
:return: A geopandas geoseries consiting of LineStrings representing the streets in EPSG:4326
'''
if measurement_coords.crs != "EPSG:4326":
raise ValueError("Make sure to pass data with EPSG:4326 projection")
long, lat = measurement_coords.x, measurement_coords.y
bounds = (lat.min(), long.min(), lat.max(), long.max())
result = make_overpy_request(
f"""
[out:json][timeout:25];
(
way['highway']['highway'!='footway']['highway'!='platform']['highway'!='steps']{bounds};
);
out body;
>;
out skel qt;
""",
retries
)
street_series = gpd.GeoSeries(
LineString(
((node.lon, node.lat) for node in way.nodes)
) for way in result.ways
).set_crs("EPSG:4326")
return street_series
[docs]def get_geoseries_blockages(measurement_coords, retries=5):
'''
Obtain the blockage shapes in the area spanned by the measurement_coords.
:param measurement_coords: A geopandas geoseries of Points(lon, lat) representing the measurement positions in a EPSG:4326 projection
:return: A geopandas geoseries consiting of Polygons representing the blockages in EPSG:4326
'''
if measurement_coords.crs != "EPSG:4326":
raise ValueError("Make sure to pass data with EPSG:4326 projection")
long, lat = measurement_coords.x, measurement_coords.y
bounds = (lat.min(), long.min(), lat.max(), long.max())
result = make_overpy_request(
f"""
[out:json][timeout:25];
(
way['building']{bounds};
relation["building"]{bounds};
);
out body;
>;
out skel qt;
""",
retries
)
blockages = gpd.GeoSeries(
Polygon(
((node.lon, node.lat) for node in way.nodes)
) for way in result.ways
).set_crs("EPSG:4326")
return blockages
[docs]def project_onto_streets(point_series, street_series, epsg="EPSG:31287", plot=False):
'''
Todo: Muss noch angepasst werden!
'''
if point_series.crs != epsg or street_series.crs != epsg:
raise ValueError("GeoSeries does not match value set by epsg argument (Default EPSG:31287)")
projected = []
for point in point_series:
street_ind = street_series.distance(point).argmin()
projected.append(
street_series.loc[street_ind].interpolate(street_series.loc[street_ind].project(point))
)
projected = gpd.GeoSeries(projected)
projected = projected.set_crs(epsg)
deviation_projection = projected.distance(point_series)
if plot:
plt.figure()
plt.title("Deviation Histogram")
deviation_projection.plot.hist(bins=50)
plt.show()
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(20, 10))
ax1.set_title("Raw Measurements")
ax2.set_title("After Projection")
ax1.scatter(point_series.x, point_series.y, label="Point Series")
clb = ax2.scatter(projected.x, projected.y, c=deviation_projection, label="Projected Series")
for street in street_series:
ax1.plot(*street.xy, color="black")
ax2.plot(*street.xy, color="black")
bar = fig.colorbar(clb)
bar.ax.set_title('Deviation [Meters]')
ax1.legend()
ax2.legend()
plt.show()
return projected, deviation_projection