forked from TUDelft-CNS-ATM/bluesky
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
segmentation_service.python.lib module changed to segmentation_service.python.lib2
- Loading branch information
mbaena
authored and
mbaena
committed
Aug 23, 2022
1 parent
3ebdbf3
commit 77b4e34
Showing
157 changed files
with
1,419 additions
and
3 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
�]�. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
�]�. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
�]�. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
�]�. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
�]�. |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import os | ||
|
||
from usepe.segmentation_service.python.lib import openair | ||
import geopandas as gpd | ||
import osmnx as ox | ||
import pandas as pd | ||
|
||
|
||
_ASP_FILE = os.path.join( | ||
os.path.abspath( os.path.dirname( __file__ ) ), "../../data/airspace/de_asp.txt" | ||
) | ||
|
||
|
||
def add_restrictions( airspaces, rules ): | ||
airspaces["z_min"] = False | ||
airspaces["z_max"] = False | ||
airspaces["speed_min"] = False | ||
airspaces["speed_max"] = False | ||
for name, data in rules["classes"].items(): | ||
airspaces.loc[airspaces["class"] == name, "z_min"] = min( data["altitude"] ) | ||
airspaces.loc[airspaces["class"] == name, "z_max"] = max( data["altitude"] ) | ||
airspaces.loc[airspaces["class"] == name, "speed_min"] = min( data["velocity"] ) | ||
airspaces.loc[airspaces["class"] == name, "speed_max"] = max( data["velocity"] ) | ||
return airspaces | ||
|
||
|
||
def get( region, rules ): | ||
airspaces = openair.to_gdf( _ASP_FILE ) | ||
airspaces = gpd.sjoin( | ||
airspaces, | ||
gpd.GeoDataFrame( {"label": ["in_region"], "geometry": [region]} ), | ||
"inner", | ||
"intersects", | ||
) | ||
airspaces = airspaces[airspaces["z_min"] < max( rules["vll"] )] | ||
airspaces = airspaces.rename( columns={"class": "type"} ) | ||
airspaces["class"] = "grey" | ||
airspaces["element_type"] = "airspace" | ||
airspaces["buffer"] = 0 | ||
airspaces = airspaces.set_index( "element_type", append=True ) | ||
airspaces = airspaces.rename_axis( index=["id", "element"] ).reorder_levels( [1, 0] ) | ||
|
||
airspaces = add_restrictions( airspaces, rules ) | ||
|
||
return airspaces[ | ||
["class", "type", "name", "geometry", "buffer", "z_min", "z_max", "speed_min", "speed_max"] | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import math | ||
|
||
from networkx.algorithms.components.connected import connected_components | ||
from shapely.geometry import Polygon, box | ||
|
||
from usepe.segmentation_service.python.lib import rectangles | ||
import geopandas as gpd | ||
import networkx as nx | ||
import pandas as pd | ||
|
||
|
||
def simplify( features, rules ): | ||
def to_edges( l ): | ||
it = iter( l ) | ||
last = next( it ) | ||
for current in it: | ||
yield last, current | ||
last = current | ||
|
||
def close_holes( poly ): | ||
if poly.interiors: | ||
return Polygon( list( poly.exterior.coords ) ) | ||
else: | ||
return poly | ||
|
||
def min_size_rect( bounds, minL ): | ||
bounds.maxx = math.ceil( bounds.maxx / minL ) * minL | ||
bounds.maxy = math.ceil( bounds.maxy / minL ) * minL | ||
bounds.minx = math.floor( bounds.minx / minL ) * minL | ||
bounds.miny = math.floor( bounds.miny / minL ) * minL | ||
poly = box( *list( bounds ) ) | ||
return poly | ||
|
||
features = features.copy() | ||
features = features.sort_index() | ||
features.geometry = [ | ||
min_size_rect( bounds, rules["min_grid"] ) | ||
for _, bounds in features.geometry.bounds.iterrows() | ||
] | ||
# features.geometry = [box(*list(bounds)) for _, bounds in features.geometry.bounds.iterrows()] | ||
|
||
neighbor_graph = nx.Graph() | ||
for _, row in features.iterrows(): | ||
classfeat = features[features["class"] == row["class"]] | ||
intersects = classfeat.geometry.intersects( row.geometry ) | ||
intersections = classfeat.intersection( row.geometry ) | ||
|
||
neighbors = classfeat[intersects & ( intersections.type != "Point" )].index.tolist() | ||
neighbor_graph.add_nodes_from( neighbors ) | ||
neighbor_graph.add_edges_from( to_edges( neighbors ) ) | ||
|
||
features["cluster"] = -1 | ||
for cluster_index, neighborhood in enumerate( connected_components( neighbor_graph ) ): | ||
for idx in neighborhood: | ||
features["cluster"].at[idx] = cluster_index | ||
|
||
simple = features.dissolve( | ||
by="cluster", | ||
aggfunc={ | ||
"class": "first", | ||
"type": lambda s: "; ".join( set( s ) ), | ||
"name": lambda s: "; ".join( set( filter( lambda x: x != "nan", s ) ) ), | ||
"z_min": "min", | ||
"z_max": "max", | ||
"speed_min": "max", | ||
"speed_max": "min", | ||
}, | ||
) | ||
simple = gpd.GeoDataFrame( simple, geometry=[close_holes( poly ) for poly in simple.geometry] ) | ||
simple = simple[simple["class"] != "grey"] # HACK remove large airspace structures | ||
return simple | ||
|
||
|
||
def deoverlap( simple, rules ): | ||
classes = rules["classes"] | ||
|
||
cutout = None | ||
stacked = None | ||
grouped = simple.groupby( "class" ) | ||
available = grouped.groups.keys() | ||
for class_name in classes: | ||
if class_name not in available: | ||
continue | ||
group = grouped.get_group( class_name ) | ||
if cutout is None: | ||
cutout = group | ||
stacked = group | ||
else: | ||
group = group.overlay( cutout, "difference" ).explode( index_parts=True ) | ||
cutout = pd.concat( [cutout, group] ) | ||
stacked = pd.concat( [stacked, group], ignore_index=True ) | ||
return stacked | ||
|
||
|
||
def fillspace( region, stacked, rules ): | ||
cutout = stacked.dissolve() | ||
region = region.difference( cutout.at[0, "geometry"] ) | ||
defClass = list( rules["classes"] )[-1] | ||
spaced = gpd.GeoDataFrame( | ||
{ | ||
"class": defClass, | ||
"type": "space", | ||
"name": "", | ||
"z_min": min( rules["classes"][defClass]["altitude"] ), | ||
"z_max": max( rules["classes"][defClass]["altitude"] ), | ||
"speed_min": min( rules["classes"][defClass]["velocity"] ), | ||
"speed_max": max( rules["classes"][defClass]["velocity"] ), | ||
"geometry": region.geoms if region.geom_type == "MultiPolygon" else [region], | ||
} | ||
) | ||
return pd.concat( [spaced, stacked], ignore_index=True ).set_crs( "EPSG:4326" ) | ||
|
||
|
||
def dissect( spaced ): | ||
segments = None | ||
for _, feature in spaced.iterrows(): | ||
rects = rectangles.decompose( feature.geometry ) | ||
decomp = gpd.GeoDataFrame( | ||
{ | ||
"class": feature["class"], | ||
"z_min": feature["z_min"], | ||
"z_max": feature["z_max"], | ||
"speed_max": feature["speed_max"], | ||
"speed_min": feature["speed_min"], | ||
"geometry": rects.geoms, | ||
} | ||
) | ||
if segments is None: | ||
segments = decomp | ||
else: | ||
segments = pd.concat( [segments, decomp], ignore_index=True ) | ||
|
||
return segments |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from collections import defaultdict | ||
|
||
import geopandas as gpd | ||
import osmnx as ox | ||
import pandas as pd | ||
|
||
|
||
def parse_rules(rules): | ||
osm_tags = defaultdict(list) | ||
for _, data in rules["ground"].items(): | ||
for key, value in data["osm"].items(): | ||
osm_tags[key].extend(value) | ||
return dict(osm_tags) | ||
|
||
|
||
def filter_osm(osm_data, rules): | ||
ground_data = [] | ||
for name, data in rules["ground"].items(): | ||
tags = data["osm"] | ||
filter = osm_data.isin(tags).any(axis=1) | ||
if not filter.any(): | ||
continue | ||
filtered = osm_data.loc[filter, ["geometry", "name"]] | ||
filtered["type"] = name | ||
filtered["class"] = data["class"] | ||
filtered["buffer"] = data["buffer"] if "buffer" in data and data["buffer"] > 1 else 1 | ||
ground_data.append(filtered) | ||
ground_data = gpd.GeoDataFrame(pd.concat(ground_data), geometry="geometry") | ||
ground_data["name"] = ground_data["name"].astype(str) | ||
ground_data["type"] = ground_data["type"].astype(str) | ||
return ground_data | ||
|
||
|
||
def buffer_regions(ground_data): | ||
buffered = ground_data.to_crs("EPSG:3035").buffer(ground_data["buffer"]) | ||
ground_data["geometry"] = buffered.to_crs("EPSG:4326") | ||
ground_data["buffer"] = ground_data["buffer"].astype(int) * -1 | ||
|
||
return ground_data | ||
|
||
|
||
def add_restrictions(ground_data, rules): | ||
ground_data["z_min"] = False | ||
ground_data["z_max"] = False | ||
ground_data["speed_min"] = False | ||
ground_data["speed_max"] = False | ||
for name, data in rules["classes"].items(): | ||
ground_data.loc[ground_data["class"] == name, "z_min"] = min(data["altitude"]) | ||
ground_data.loc[ground_data["class"] == name, "z_max"] = max(data["altitude"]) | ||
ground_data.loc[ground_data["class"] == name, "speed_min"] = min(data["velocity"]) | ||
ground_data.loc[ground_data["class"] == name, "speed_max"] = max(data["velocity"]) | ||
return ground_data | ||
|
||
|
||
def get(region, rules): | ||
osm_tags = parse_rules(rules) | ||
osm_data = ox.geometries_from_polygon(region, osm_tags) | ||
gnd_data = filter_osm(osm_data, rules) | ||
gnd_data = buffer_regions(gnd_data) | ||
gnd_data = gnd_data.rename_axis(index=["element", "id"]) | ||
gnd_data = add_restrictions(gnd_data, rules) | ||
|
||
return gnd_data[ | ||
["class", "type", "name", "geometry", "buffer", "z_min", "z_max", "speed_min", "speed_max"] | ||
] |
Oops, something went wrong.