def build_apron_areas(tile, airport_layer, dico_airports): for airport in dico_airports: wayid_list = dico_airports[airport]['apron'] aprons = [] for wayid in wayid_list: try: pol = geometry.Polygon( numpy.round( numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([[tile.lon, tile.lat]]), 7)) if not pol.is_valid: UI.vprint( 2, "Unable to turn apron area to polygon, close to", airport_layer.dicosmn[airport_layer.dicosmw[wayid][0]]) continue except: UI.vprint( 2, "Unable to turn apron area to polygon, close to", airport_layer.dicosmn[airport_layer.dicosmw[wayid][0]]) continue aprons.append(pol) aprons = VECT.ensure_MultiPolygon(ops.cascaded_union(aprons)) dico_airports[airport]['apron'] = (aprons, dico_airports[airport]['apron']) return
def build_taxiway_areas(tile, airport_layer, dico_airports): for airport in dico_airports: wayid_list = dico_airports[airport]['taxiway'] taxiways = geometry.MultiLineString([ geometry.LineString( numpy.round( numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([[tile.lon, tile.lat]]), 7)) for wayid in wayid_list ]) taxiways = VECT.ensure_MultiPolygon( VECT.improved_buffer(taxiways, 15, 3, 0.5)) dico_airports[airport]['taxiway'] = (taxiways, dico_airports[airport]['taxiway']) return
def encode_hangars(tile, dico_airports, vector_map, patches_list): seeds = [] for airport in dico_airports: if airport in patches_list: continue for pol in VECT.ensure_MultiPolygon( VECT.cut_to_tile(dico_airports[airport]['hangar'])): way = numpy.array(pol.exterior.coords) alti_way = numpy.ones( (len(way), 1)) * numpy.min(tile.dem.alt_vec(way)) vector_map.insert_way(numpy.hstack([way, alti_way]), 'HANGAR', check=True) seeds.append(numpy.array(pol.representative_point())) if seeds: if 'HANGAR' in vector_map.seeds: vector_map.seeds['HANGAR'] += seeds else: vector_map.seeds['HANGAR'] = seeds return 1
def build_hangar_areas(tile, airport_layer, dico_airports): for airport in dico_airports: wayid_list = dico_airports[airport]['hangar'] hangars = [] for wayid in wayid_list: try: pol = geometry.Polygon( numpy.round( numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([[tile.lon, tile.lat]]), 7)) if not pol.is_valid: continue except: UI.vprint( 2, "Unable to turn hangar area to polygon, close to", airport_layer.dicosmn[airport_layer.dicosmw[wayid][0]]) continue hangars.append(pol) hangars = VECT.ensure_MultiPolygon( VECT.improved_buffer(ops.cascaded_union(hangars), 2, 1, 0.5)) dico_airports[airport]['hangar'] = hangars
def update_airport_boundaries(tile, dico_airports): for airport in dico_airports: apt = dico_airports[airport] boundary = ops.cascaded_union([ apt['taxiway'][0], apt['apron'][0], apt['hangar'], apt['runway'][0] ]) if apt['boundary']: apt['boundary'] = VECT.ensure_MultiPolygon( ops.cascaded_union([ affinity.translate(apt['boundary'], -tile.lon, -tile.lat), boundary ]).buffer(0).simplify(0.00001)) else: apt['boundary'] = VECT.ensure_MultiPolygon( boundary.buffer(0).simplify(0.00001)) # pickle dico_airports for later use in Step 2 (apt_curv_tol) and Step 3 (cover_airports_with_high_res) try: with open(FNAMES.apt_file(tile), 'wb') as outf: pickle.dump(dico_airports, outf) except: UI.vprint(1, "WARNING: Could not save airport info to file", FNAMES.apt_file(tile)) return
def road_is_too_much_banked(way, filtered_segs): (col, row) = numpy.minimum(numpy.maximum(numpy.round(way[0] * 1000), 0), 1000) if apt_array[int(1000 - row), int(col)]: return True (col, row) = numpy.minimum(numpy.maximum(numpy.round(way[-1] * 1000), 0), 1000) if apt_array[int(1000 - row), int(col)]: return True if filtered_segs >= tile.max_levelled_segs: return False return (numpy.abs( tile.dem.alt_vec(way) - tile.dem.alt_vec(VECT.shift_way(way, tile.lane_width))) >= tile.road_banking_limit).any()
def include_sea(vector_map, tile): UI.vprint(0, "-> Dealing with coastline") sea_layer = OSM.OSM_layer() custom_coastline = FNAMES.custom_coastline(tile.lat, tile.lon) if os.path.isfile(custom_coastline): sea_layer.update_dicosm(custom_coastline, target_tags=None) else: queries = ['way["natural"="coastline"]'] tags_of_interest = [] if not OSM.OSM_queries_to_OSM_layer(queries, sea_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='coastline'): return 0 coastline = OSM.OSM_to_MultiLineString(sea_layer, tile.lat, tile.lon, None) if not coastline.is_empty: # 1) encoding the coastline UI.vprint(1, " * Encoding coastline.") vector_map.encode_MultiLineString(VECT.cut_to_tile( coastline, strictly_inside=True), tile.dem.alt_vec, 'SEA', check=True, refine=False) UI.vprint(3, "...done.") # 2) finding seeds (transform multilinestring coastline to polygon coastline # linemerge being expensive we first set aside what is already known to be closed loops UI.vprint(1, " * Reconstructing its topology.") loops = geometry.MultiLineString( [line for line in coastline.geoms if line.is_ring]) remainder = VECT.ensure_MultiLineString( VECT.cut_to_tile(geometry.MultiLineString( [line for line in coastline.geoms if not line.is_ring]), strictly_inside=True)) UI.vprint(3, "Linemerge...") if not remainder.is_empty: remainder = VECT.ensure_MultiLineString(ops.linemerge(remainder)) UI.vprint(3, "...done.") coastline = geometry.MultiLineString([line for line in remainder] + [line for line in loops]) sea_area = VECT.ensure_MultiPolygon( VECT.coastline_to_MultiPolygon(coastline, tile.lat, tile.lon)) if sea_area.geoms: UI.vprint(1, " Found ", len(sea_area.geoms), "contiguous patch(es).") for polygon in sea_area.geoms: seed = numpy.array(polygon.representative_point()) if 'SEA' in vector_map.seeds: vector_map.seeds['SEA'].append(seed) else: vector_map.seeds['SEA'] = [seed]
def include_water(vector_map, tile): UI.vprint(0, "-> Dealing with inland water") water_layer = OSM.OSM_layer() custom_water = FNAMES.custom_water(tile.lat, tile.lon) if os.path.isfile(custom_water): water_layer.update_dicosm(custom_water, target_tags=None) else: queries = [ 'rel["natural"="water"]', 'rel["waterway"="riverbank"]', 'way["natural"="water"]', 'way["waterway"="riverbank"]', 'way["waterway"="dock"]' ] tags_of_interest = ["name"] if not OSM.OSM_queries_to_OSM_layer(queries, water_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='water'): return 0 UI.vprint(1, " * Building water multipolygon.") water_area = OSM.OSM_to_MultiPolygon(water_layer, tile.lat, tile.lon) if not water_area.is_empty: UI.vprint(1, " Cleaning it.") try: (idx_water, dico_water) = VECT.MultiPolygon_to_Indexed_Polygons( water_area, merge_overlappings=tile.clean_bad_geometries, limit=VECT.max_pols_for_merge) except: return 0 UI.vprint( 2, " Number of water Multipolygons : " + str(len(dico_water))) UI.vprint(1, " Encoding it.") vector_map.encode_MultiPolygon(dico_water, tile.dem.alt_vec, 'WATER', area_limit=tile.min_area / 10000, simplify=0.00001, check=True) return 1
def include_airports(vector_map, tile, patches_area): # patches_area if not None is the extent to substract from runway_area # we enlarge it (local copy) slightly for security patches_area = patches_area.buffer(0.00002) UI.vprint(0, "-> Dealing with airports") airport_layer = OSM.OSM_layer() queries = [('rel["aeroway"="runway"]', 'rel["aeroway"="taxiway"]', 'rel["aeroway"="apron"]', 'way["aeroway"="runway"]', 'way["aeroway"="taxiway"]', 'way["aeroway"="apron"]')] tags_of_interest = ["all"] if not OSM.OSM_queries_to_OSM_layer(queries, airport_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='airports'): return 0 # Runway and taxiway center lines (they will be incorporated to ensure triangles # are not too badly aligned with these lines (improves removal of bumpiness) runway_network = OSM.OSM_to_MultiLineString(airport_layer, tile.lat, tile.lon, []) # Buffer these for later smoothing runway_area = VECT.improved_buffer(runway_network, 0.0003, 0.0001, 0.00001) if not runway_area: return 0 runway_area = runway_area.difference(patches_area).buffer(0).simplify( 0.00001) runway_network = runway_network.difference(patches_area) # Now we encode in vector_map vector_map.encode_MultiLineString(runway_network, tile.dem.alt_vec, 'DUMMY', check=True, refine=20) vector_map.encode_MultiPolygon(runway_area, tile.dem.alt_vec, 'SMOOTHED_ALT', check=True, refine=50) return 1
def include_roads(vector_map, tile, apt_array, apt_area): def road_is_too_much_banked(way, filtered_segs): (col, row) = numpy.minimum(numpy.maximum(numpy.round(way[0] * 1000), 0), 1000) if apt_array[int(1000 - row), int(col)]: return True (col, row) = numpy.minimum(numpy.maximum(numpy.round(way[-1] * 1000), 0), 1000) if apt_array[int(1000 - row), int(col)]: return True if filtered_segs >= tile.max_levelled_segs: return False return (numpy.abs( tile.dem.alt_vec(way) - tile.dem.alt_vec(VECT.shift_way(way, tile.lane_width))) >= tile.road_banking_limit).any() def alt_vec_shift(way): return tile.dem.alt_vec(VECT.shift_way(way, tile.lane_width)) if not tile.road_level: return UI.vprint(0, "-> Dealing with roads") tags_of_interest = ["bridge", "tunnel"] #Need to evaluate if including bridges is better or worse tags_for_exclusion = set(["bridge", "tunnel"]) #tags_for_exclusion=set(["tunnel"]) road_layer = OSM.OSM_layer() queries = [ 'way["highway"="motorway"]', 'way["highway"="trunk"]', 'way["highway"="primary"]', 'way["highway"="secondary"]', 'way["railway"="rail"]', 'way["railway"="narrow_gauge"]' ] if not OSM.OSM_queries_to_OSM_layer(queries, road_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='big_roads'): return 0 UI.vprint(1, " * Checking which large roads need levelling.") (road_network_banked, road_network_flat) = OSM.OSM_to_MultiLineString( road_layer, tile.lat, tile.lon, tags_for_exclusion, road_is_too_much_banked) if UI.red_flag: return 0 if tile.road_level >= 2: road_layer = OSM.OSM_layer() queries=[\ 'way["highway"="tertiary"]'] if tile.road_level >= 3: queries += [ 'way["highway"="unclassified"]', 'way["highway"="residential"]' ] if tile.road_level >= 4: queries += ['way["highway"="service"]'] if tile.road_level >= 5: queries += ['way["highway"="track"]'] if not OSM.OSM_queries_to_OSM_layer(queries, road_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='small_roads'): return 0 UI.vprint(1, " * Checking which smaller roads need levelling.") timer = time.time() (road_network_banked_2,road_network_flat_2)=OSM.OSM_to_MultiLineString(road_layer,\ tile.lat,tile.lon,tags_for_exclusion,road_is_too_much_banked) UI.vprint(3, "Time for check :", time.time() - timer) road_network_banked = geometry.MultiLineString( list(road_network_banked) + list(road_network_banked_2)) if not road_network_banked.is_empty: UI.vprint(1, " * Buffering banked road network as multipolygon.") timer = time.time() road_area = VECT.improved_buffer(road_network_banked.difference( VECT.improved_buffer(apt_area, tile.lane_width + 2, 0, 0)), tile.lane_width, 2, 0.5, show_progress=True) UI.vprint(3, "Time for improved buffering:", time.time() - timer) if UI.red_flag: return 0 UI.vprint(1, " Encoding it.") vector_map.encode_MultiPolygon(road_area, alt_vec_shift, 'INTERP_ALT', check=True, refine=100) if UI.red_flag: return 0 if not road_network_flat.is_empty: road_network_flat = road_network_flat.difference( VECT.improved_buffer(apt_area, 15, 0, 0)).simplify(0.00001) UI.vprint( 1, " * Encoding the remaining primary road network as linestrings." ) vector_map.encode_MultiLineString(road_network_flat, tile.dem.alt_vec, 'DUMMY', check=True) return 1
def include_roads(vector_map, tile): if not tile.road_level: return UI.vprint(0, "-> Dealing with roads") tags_of_interest = ["bridge", "tunnel"] #Need to evaluate if including bridges is better or worse tags_for_exclusion = set(["bridge", "tunnel"]) #tags_for_exclusion=set(["tunnel"]) road_layer = OSM.OSM_layer() queries = [ 'way["highway"="motorway"]', 'way["highway"="trunk"]', 'way["highway"="primary"]', 'way["highway"="secondary"]', 'way["railway"="rail"]', 'way["railway"="narrow_gauge"]' ] if not OSM.OSM_queries_to_OSM_layer(queries, road_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='big_roads'): return 0 UI.vprint(1, " * Checking which large roads need levelling.") (road_network_banked, road_network_flat) = OSM.OSM_to_MultiLineString( road_layer, tile.lat, tile.lon, tags_for_exclusion, lambda way: tile.dem.way_is_too_much_banked( way, tile.road_banking_limit)) if UI.red_flag: return 0 if tile.road_level >= 2: road_layer = OSM.OSM_layer() queries=[\ 'way["highway"="tertiary"]'] if tile.road_level >= 3: queries += [ 'way["highway"="unclassified"]', 'way["highway"="residential"]' ] if tile.road_level >= 4: queries += ['way["highway"="service"]'] if tile.road_level >= 5: queries += ['way["highway"="track"]'] if not OSM.OSM_queries_to_OSM_layer(queries, road_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='small_roads'): return 0 UI.vprint(1, " * Checking which smaller roads need levelling.") timer = time.time() (road_network_banked_2,road_network_flat_2)=OSM.OSM_to_MultiLineString(road_layer,\ tile.lat,tile.lon,tags_for_exclusion,lambda way: tile.dem.way_is_too_much_banked(way,tile.road_banking_limit),limit_segs=tile.max_levelled_segs) UI.vprint(3, "Time for check :", time.time() - timer) road_network_banked = geometry.MultiLineString( list(road_network_banked) + list(road_network_banked_2)).simplify(0.000005) if not road_network_banked.is_empty: UI.vprint(1, " * Buffering banked road network as multipolygon.") timer = time.time() road_area = VECT.improved_buffer(road_network_banked, 0.00004, 0.00002, 0.000005) UI.vprint(3, "Time for improved buffering:", time.time() - timer) if UI.red_flag: return 0 UI.vprint(1, " Encoding it.") vector_map.encode_MultiPolygon(road_area, tile.dem.alt_vec_road, 'INTERP_ALT', check=True, refine=False) if UI.red_flag: return 0 if not road_network_flat.is_empty: road_network_flat = road_network_flat.simplify( 0.00001) #.difference(road_area) UI.vprint( 1, " * Encoding the remaining primary road network as linestrings." ) vector_map.encode_MultiLineString(road_network_flat, tile.dem.alt_vec_road, 'DUMMY', check=True) return 1
def build_poly_file(tile): UI.red_flag = 0 UI.logprint("Step 1 for tile lat=", tile.lat, ", lon=", tile.lon, ": starting.") UI.vprint( 0, "\nStep 1 : Building vector data for tile " + FNAMES.short_latlon(tile.lat, tile.lon) + " : \n--------\n") timer = time.time() if not os.path.exists(tile.build_dir): os.makedirs(tile.build_dir) if not os.path.exists(FNAMES.osm_dir(tile.lat, tile.lon)): os.makedirs(FNAMES.osm_dir(tile.lat, tile.lon)) node_file = FNAMES.input_node_file(tile) poly_file = FNAMES.input_poly_file(tile) vector_map = VECT.Vector_Map() tile.ensure_elevation_data() if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Patches patches_area = include_patches(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Airports include_airports(vector_map, tile, patches_area) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Roads include_roads(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Sea include_sea(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Water include_water(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Buildings # include_buildings(vector_map) # if UI.red_flag: UI.exit_message_and_bottom_line(); return 0 # Orthogrid UI.vprint(0, "-> Inserting edges related to the orthophotos grid") xgrid = set() # x coordinates of vertical grid lines ygrid = set() # y coordinates of horizontal grid lines (til_xul, til_yul) = GEO.wgs84_to_orthogrid(tile.lat + 1, tile.lon, tile.mesh_zl) (til_xlr, til_ylr) = GEO.wgs84_to_orthogrid(tile.lat, tile.lon + 1, tile.mesh_zl) for til_x in range(til_xul + 16, til_xlr + 1, 16): pos_x = (til_x / (2**(tile.mesh_zl - 1)) - 1) xgrid.add(pos_x * 180 - tile.lon) for til_y in range(til_yul + 16, til_ylr + 1, 16): pos_y = (1 - (til_y) / (2**(tile.mesh_zl - 1))) ygrid.add(360 / pi * atan(exp(pi * pos_y)) - 90 - tile.lat) xgrid.add(0) xgrid.add(1) ygrid.add(0) ygrid.add(1) xgrid = list(sorted(xgrid)) ygrid = list(sorted(ygrid)) ortho_network = geometry.MultiLineString( [geometry.LineString([(x, 0), (x, 1)]) for x in xgrid] + [geometry.LineString([(0, y), (1, y)]) for y in ygrid]) vector_map.encode_MultiLineString(ortho_network, tile.dem.alt_vec, 'DUMMY', check=True, skip_cut=True) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Gluing edges UI.vprint(0, "-> Inserting additional boundary edges for gluing") segs = 2500 gluing_network=geometry.MultiLineString([\ geometry.LineString([(x,0) for x in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(x,1) for x in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(0,y) for y in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(1,y) for y in numpy.arange(0,segs+1)/segs])]) vector_map.encode_MultiLineString(gluing_network, tile.dem.alt_vec, 'DUMMY', check=True, skip_cut=True) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 UI.vprint(0, "-> Transcription to the files ", poly_file, "and .node") if not vector_map.seeds: if tile.dem.alt_dem.max() >= 1: vector_map.seeds['SEA'] = [numpy.array([1000, 1000])] else: vector_map.seeds['SEA'] = [numpy.array([0.5, 0.5])] vector_map.write_node_file(node_file) vector_map.write_poly_file(poly_file) UI.vprint(1, "\nFinal number of constrained edges :", len(vector_map.dico_edges)) UI.timings_and_bottom_line(timer) UI.logprint("Step 1 for tile lat=", tile.lat, ", lon=", tile.lon, ": normal exit.") return 1
def zone_list_to_ortho_dico(tile): # tile.zone_list is a list of 3-uples of the form ([(lat0,lat0),...(latN,lonN),zoomlevel,provider_code) # where higher lines have priority over lower ones. masks_im=Image.new("L",(4096,4096),'black') masks_draw=ImageDraw.Draw(masks_im) airport_array=numpy.zeros((4096,4096),dtype=numpy.bool) if tile.cover_airports_with_highres: UI.vprint(1,"-> Checking airport locations for upgraded zoomlevel.") airport_layer=OSM.OSM_layer() queries=[('rel["aeroway"="runway"]','rel["aeroway"="taxiway"]','rel["aeroway"="apron"]', 'way["aeroway"="runway"]','way["aeroway"="taxiway"]','way["aeroway"="apron"]')] tags_of_interest=["all"] if not OSM.OSM_queries_to_OSM_layer(queries,airport_layer,tile.lat,tile.lon,tags_of_interest,cached_suffix='airports'): return 0 runway_network=OSM.OSM_to_MultiLineString(airport_layer,tile.lat,tile.lon) runway_area=VECT.improved_buffer(runway_network,0.0003,0.0001,0.00001) runway_area=VECT.ensure_MultiPolygon(runway_area) for polygon in runway_area.geoms: (xmin,ymin,xmax,ymax)=polygon.bounds # extension xmin-=1000*tile.cover_extent*GEO.m_to_lon(tile.lat) xmax+=1000*tile.cover_extent*GEO.m_to_lon(tile.lat) ymax+=1000*tile.cover_extent*GEO.m_to_lat ymin-=1000*tile.cover_extent*GEO.m_to_lat # round off to texture boundaries at tile.cover_zl zoomlevel (til_x_left,til_y_top)=GEO.wgs84_to_orthogrid(ymax+tile.lat,xmin+tile.lon,tile.cover_zl) (ymax,xmin)=GEO.gtile_to_wgs84(til_x_left,til_y_top,tile.cover_zl) ymax-=tile.lat; xmin-=tile.lon (til_x_left,til_y_top)=GEO.wgs84_to_orthogrid(ymin+tile.lat,xmax+tile.lon,tile.cover_zl) (ymin,xmax)=GEO.gtile_to_wgs84(til_x_left+16,til_y_top+16,tile.cover_zl) ymin-=tile.lat; xmax-=tile.lon # mark to airport_array colmin=round(xmin*4095) colmax=round(xmax*4095) rowmax=round((1-ymin)*4095) rowmin=round((1-ymax)*4095) airport_array[rowmin:rowmax+1,colmin:colmax+1]=1 del(airport_layer) del(runway_network) del(runway_area) dico_tmp={} dico_customzl={} i=1 base_zone=((tile.lat,tile.lon,tile.lat,tile.lon+1,tile.lat+1,tile.lon+1,tile.lat+1,tile.lon,tile.lat,tile.lon),tile.default_zl,tile.default_website) for region in [base_zone]+tile.zone_list[::-1]: dico_tmp[i]=(region[1],region[2]) pol=[(round((x-tile.lon)*4095),round((tile.lat+1-y)*4095)) for (x,y) in zip(region[0][1::2],region[0][::2])] masks_draw.polygon(pol,fill=i) i+=1 til_x_min,til_y_min=GEO.wgs84_to_orthogrid(tile.lat+1,tile.lon,tile.mesh_zl) til_x_max,til_y_max=GEO.wgs84_to_orthogrid(tile.lat,tile.lon+1,tile.mesh_zl) for til_x in range(til_x_min,til_x_max+1,16): for til_y in range(til_y_min,til_y_max+1,16): (latp,lonp)=GEO.gtile_to_wgs84(til_x+8,til_y+8,tile.mesh_zl) lonp=max(min(lonp,tile.lon+1),tile.lon) latp=max(min(latp,tile.lat+1),tile.lat) x=round((lonp-tile.lon)*4095) y=round((tile.lat+1-latp)*4095) (zoomlevel,provider_code)=dico_tmp[masks_im.getpixel((x,y))] if airport_array[y,x]: zoomlevel=max(zoomlevel,tile.cover_zl) til_x_text=16*(int(til_x/2**(tile.mesh_zl-zoomlevel))//16) til_y_text=16*(int(til_y/2**(tile.mesh_zl-zoomlevel))//16) dico_customzl[(til_x,til_y)]=(til_x_text,til_y_text,zoomlevel,provider_code) return dico_customzl
def keep_obj8(lat_anchor, lon_anchor, alt_anchor, heading_anchor, objfile_name, vector_map, tile): dico_idx_nodes = {} idx_node = 0 dico_index = {} index = 0 latscale = GEO.m_to_lat lonscale = latscale / cos(lat_anchor * pi / 180) f = open(objfile_name, 'r') for line in f.readlines(): if line[0:2] == 'VT': (xo, yo, zo) = [float(s) for s in line.split()[1:4]] Xo = xo * cos(heading_anchor * pi / 180) - zo * sin( heading_anchor * pi / 180) Zo = xo * sin(heading_anchor * pi / 180) + zo * cos( heading_anchor * pi / 180) y = numpy.round(lat_anchor - latscale * float(Zo) - tile.lat, 7) x = numpy.round(lon_anchor + lonscale * float(Xo) - tile.lon, 7) z = yo + alt_anchor dico_idx_nodes[idx_node] = vector_map.insert_node(x, y, z) idx_node += 1 elif line[0:3] == 'IDX': dico_index[index] = [int(x) for x in line.split()[1:]] index += 1 elif line[0:4] == 'TRIS': (offset, count) = [int(x) for x in line.split()[1:3]] list = [] count_tmp = 0 try: polist = [] while count_tmp < count: list += dico_index[offset] count_tmp += len(dico_index[offset]) offset += 1 for j in range(count // 3): (a, b, c) = [dico_idx_nodes[x] for x in list[3 * j:3 * j + 3]] if a == b or a == c or b == c: continue for (initp, endp) in ((a, b), (b, c), (c, a)): vector_map.insert_edge( initp, endp, vector_map.dico_attributes['INTERP_ALT'], check=True) seed = (numpy.array(vector_map.nodes_dico[a]) + numpy.array(vector_map.nodes_dico[b]) + numpy.array(vector_map.nodes_dico[c])) / 3 if 'INTERP_ALT' in vector_map.seeds: vector_map.seeds['INTERP_ALT'].append(seed) else: vector_map.seeds['INTERP_ALT'] = [seed] polist.append( geometry.Polygon([ vector_map.nodes_dico[a], vector_map.nodes_dico[b], vector_map.nodes_dico[c], vector_map.nodes_dico[a] ])) multipol = VECT.ensure_MultiPolygon(ops.cascaded_union(polist)) except: pass f.close() return multipol
def include_water(vector_map, tile): large_lake_threshold = tile.max_area * 1e6 / (GEO.lat_to_m * GEO.lon_to_m(tile.lat + 0.5)) def filter_large_lakes(pol, osmid, dicosmtags): if pol.area < large_lake_threshold: return False area = int(pol.area * GEO.lat_to_m * GEO.lon_to_m(tile.lat + 0.5) / 1e6) if (osmid in dicosmtags) and ('name' in dicosmtags[osmid]): if (dicosmtags[osmid]['name'] in good_imagery_list): UI.vprint(1, " * ", dicosmtags[osmid]['name'], "kept will complete imagery although it is", area, "km^2.") return False else: UI.vprint( 1, " * ", dicosmtags[osmid]['name'], "will be masked like the sea due to its large area of", area, "km^2.") return True else: pt = pol.exterior.coords[ 0] if 'Multi' not in pol.geom_type else pol[0].exterior.coords[ 0] UI.vprint(1, " * ", "Some large OSM water patch close to lat=", '{:.2f}'.format(pt[1] + tile.lon), "lon=", '{:.2f}'.format(pt[0] + tile.lat), "will be masked due to its large area of", area, "km^2.") return True UI.vprint(0, "-> Dealing with inland water") water_layer = OSM.OSM_layer() custom_water = FNAMES.custom_water(tile.lat, tile.lon) custom_water_dir = FNAMES.custom_water_dir(tile.lat, tile.lon) if os.path.isfile(custom_water): UI.vprint(1, " * User defined custom water data detected.") water_layer.update_dicosm(custom_water, input_tags=None, target_tags=None) elif os.path.isdir(custom_water_dir): UI.vprint( 1, " * User defined custom water data detected (multiple files).") for osm_file in os.listdir(custom_water_dir): UI.vprint(2, " ", osm_file) water_layer.update_dicosm(os.path.join(custom_water_dir, osm_file), input_tags=None, target_tags=None) water_layer.write_to_file(custom_water) else: queries = [ 'rel["natural"="water"]', 'rel["waterway"="riverbank"]', 'way["natural"="water"]', 'way["waterway"="riverbank"]', 'way["waterway"="dock"]' ] tags_of_interest = ["name"] if not OSM.OSM_queries_to_OSM_layer(queries, water_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='water'): return 0 UI.vprint(1, " * Building water multipolygon.") (water_area, sea_equiv_area) = OSM.OSM_to_MultiPolygon(water_layer, tile.lat, tile.lon, filter_large_lakes) if not water_area.is_empty: UI.vprint(1, " Cleaning it.") try: (idx_water, dico_water) = VECT.MultiPolygon_to_Indexed_Polygons( water_area, merge_overlappings=tile.clean_bad_geometries) except: return 0 UI.vprint( 2, " Number of water Multipolygons : " + str(len(dico_water))) UI.vprint(1, " Encoding it.") vector_map.encode_MultiPolygon(dico_water, tile.dem.alt_vec, 'WATER', area_limit=tile.min_area / 10000, simplify=tile.water_simplification * GEO.m_to_lat, check=True) if not sea_equiv_area.is_empty: UI.vprint( 1, " Separate treatment for larger pieces requiring masks.") try: (idx_water, dico_water) = VECT.MultiPolygon_to_Indexed_Polygons( sea_equiv_area, merge_overlappings=tile.clean_bad_geometries) except: return 0 UI.vprint( 2, " Number of water Multipolygons : " + str(len(dico_water))) UI.vprint(1, " Encoding them.") vector_map.encode_MultiPolygon(dico_water, tile.dem.alt_vec, 'SEA_EQUIV', area_limit=tile.min_area / 10000, simplify=tile.water_simplification * GEO.m_to_lat, check=True) return 1
def alt_vec_shift(way): return tile.dem.alt_vec(VECT.shift_way(way, tile.lane_width))
def build_poly_file(tile): if UI.is_working: return 0 UI.is_working = 1 UI.red_flag = 0 # in case that was forgotten by the user tile.iterate = 0 # update the lat/lon scaling factor in VECT VECT.scalx = cos((tile.lat + 0.5) * pi / 180) # Let's go ! UI.logprint("Step 1 for tile lat=", tile.lat, ", lon=", tile.lon, ": starting.") UI.vprint( 0, "\nStep 1 : Building vector data for tile " + FNAMES.short_latlon(tile.lat, tile.lon) + " : \n--------\n") timer = time.time() if not os.path.exists(tile.build_dir): os.makedirs(tile.build_dir) if not os.path.exists(FNAMES.osm_dir(tile.lat, tile.lon)): os.makedirs(FNAMES.osm_dir(tile.lat, tile.lon)) node_file = FNAMES.input_node_file(tile) poly_file = FNAMES.input_poly_file(tile) vector_map = VECT.Vector_Map() if UI.red_flag: UI.exit_message_and_bottom_line() return 0 if O4_ESP_Globals.build_for_ESP and os.path.isfile( O4_Config_Utils.ESP_scenproc_loc): include_scenproc(tile) # Airports (apt_array, apt_area) = include_airports(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Roads include_roads(vector_map, tile, apt_array, apt_area) if tile.road_level: UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Sea include_sea(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Water include_water(vector_map, tile) UI.vprint(1, " Number of edges at this point:", len(vector_map.dico_edges)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Buildings # include_buildings(vector_map) # if UI.red_flag: UI.exit_message_and_bottom_line(); return 0 # Orthogrid UI.vprint(0, "-> Inserting edges related to the orthophotos grid") xgrid = set() # x coordinates of vertical grid lines ygrid = set() # y coordinates of horizontal grid lines (til_xul, til_yul) = GEO.wgs84_to_orthogrid(tile.lat + 1, tile.lon, tile.mesh_zl) (til_xlr, til_ylr) = GEO.wgs84_to_orthogrid(tile.lat, tile.lon + 1, tile.mesh_zl) for til_x in range(til_xul + 16, til_xlr + 1, 16): pos_x = (til_x / (2**(tile.mesh_zl - 1)) - 1) xgrid.add(pos_x * 180 - tile.lon) for til_y in range(til_yul + 16, til_ylr + 1, 16): pos_y = (1 - (til_y) / (2**(tile.mesh_zl - 1))) ygrid.add(360 / pi * atan(exp(pi * pos_y)) - 90 - tile.lat) xgrid.add(0) xgrid.add(1) ygrid.add(0) ygrid.add(1) xgrid = list(sorted(xgrid)) ygrid = list(sorted(ygrid)) eps = 2**-5 ortho_network = geometry.MultiLineString( [geometry.LineString([(x, 0.0 - eps), (x, 1.0 + eps)]) for x in xgrid] + [geometry.LineString([(0.0 - eps, y), (1.0 + eps, y)]) for y in ygrid]) vector_map.encode_MultiLineString(ortho_network, tile.dem.alt_vec, 'DUMMY', check=True, skip_cut=True) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 # Gluing edges UI.vprint(0, "-> Inserting additional boundary edges for gluing") segs = 2048 gluing_network=geometry.MultiLineString([\ geometry.LineString([(x,0) for x in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(x,1) for x in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(0,y) for y in numpy.arange(0,segs+1)/segs]),\ geometry.LineString([(1,y) for y in numpy.arange(0,segs+1)/segs])]) vector_map.encode_MultiLineString(gluing_network, tile.dem.alt_vec, 'DUMMY', check=True, skip_cut=True) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 UI.vprint(0, "-> Transcription to the files ", poly_file, "and .node") if not vector_map.seeds: if tile.dem.alt_dem.max() >= 1: vector_map.seeds['SEA'] = [numpy.array([1000, 1000])] else: vector_map.seeds['SEA'] = [numpy.array([0.5, 0.5])] vector_map.snap_to_grid(15) vector_map.write_node_file(node_file) vector_map.write_poly_file(poly_file) UI.vprint(1, "\nFinal number of constrained edges :", len(vector_map.dico_edges)) UI.timings_and_bottom_line(timer) UI.logprint("Step 1 for tile lat=", tile.lat, ", lon=", tile.lon, ": normal exit.") return 1
def sort_and_reconstruct_runways(tile, airport_layer, dico_airports): ### Runways in OSM are either encoded as linear features or as area features, and sometimes both for the same runway. Here we identify them and ### remove duplicates. Runways of linear type are also often split in OSM between multiple parts (displaced threshold etc), we also group them ### together in this funcion. for airport in dico_airports: ## Distinction between linear and area runways runways_as_area = [ ] # runways that are encoded in OSM as a polygon around their boundary runways_as_line = [ ] # runways that are encoded in OSM as a linestrings linear = [ ] # temporary list containing parts (displaced threshold, etc) of OSM runways as linestrings linear_width = [ ] # whenever the width tag appears for runways that are linear features, if not we'll try to guess the width from the length for wayid in dico_airports[airport]['runway']: if airport_layer.dicosmw[wayid][0] == airport_layer.dicosmw[wayid][ -1]: runway_pol = geometry.Polygon( numpy.round( numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([tile.lon, tile.lat]), 7)) if not runway_pol.is_empty and runway_pol.is_valid and runway_pol.area > 1e-7: runway_pol_rect = VECT.min_bounding_rectangle(runway_pol) if wayid not in airport_layer.dicosmtags[ 'w'] or 'custom' not in airport_layer.dicosmtags[ 'w'][wayid]: discrep = runway_pol_rect.hausdorff_distance( runway_pol) if discrep > 0.0008: UI.logprint( "Bad runway (geometry too far from a rectangle) close to", airport, "at", dico_airports[airport]['repr_node']) UI.vprint( 1, " !Bad runway (geometry too far from a rectangle) close to", airport, "at", dico_airports[airport]['repr_node']) UI.vprint( 1, " !You may correct it editing the file ", FNAMES.osm_cached(tile.lat, tile.lon, 'airports'), "in JOSM.") continue rectangle = numpy.array( VECT.min_bounding_rectangle( runway_pol).exterior.coords) if VECT.length_in_meters( rectangle[0:2]) < VECT.length_in_meters( rectangle[1:3]): runway_start = (rectangle[0] + rectangle[1]) / 2 runway_end = (rectangle[2] + rectangle[3]) / 2 runway_width = VECT.length_in_meters(rectangle[0:2]) else: runway_start = (rectangle[1] + rectangle[2]) / 2 runway_end = (rectangle[0] + rectangle[3]) / 2 runway_width = VECT.length_in_meters(rectangle[1:3]) runways_as_area.append( (runway_pol, runway_start, runway_end, runway_width)) else: UI.logprint( 1, "Bad runway (geometry invalid or going back over itself) close to", airport, "at", dico_airports[airport]['repr_node']) UI.vprint( 1, " !Bad runway (geometry invalid or going back over itself) close to", airport, "at", dico_airports[airport]['repr_node']) UI.vprint( 1, " !You may correct it editing the file ", FNAMES.osm_cached(tile.lat, tile.lon, 'airports'), "in JOSM.") continue else: linear.append(airport_layer.dicosmw[wayid]) try: linear_width.append( float(airport_layer.dicosmtags['w'][wayid]['width'])) except: linear_width.append( 0 ) # 0 is just a mark for non existing data, a fictive length will be given later based on the runway length ## Line merge runway parts defined as linear features runway_parts_are_grouped = False while not runway_parts_are_grouped: runway_parts_are_grouped = True for i in range(len(linear) - 1): dir_i = numpy.arctan2( *(numpy.array(airport_layer.dicosmn[linear[i][-1]]) - numpy.array(airport_layer.dicosmn[linear[i][0]]))) for j in range(i + 1, len(linear)): dir_j = numpy.arctan2( *(numpy.array(airport_layer.dicosmn[linear[j][-1]]) - numpy.array(airport_layer.dicosmn[linear[j][0]]))) # Some different runways may share a common end-point in OSM, in this case we don't want to group them into a single one if not numpy.min( numpy.abs( numpy.array([-2 * pi, -pi, 0, pi, 2 * pi]) - (dir_i - dir_j))) < 0.2: continue if linear[i][-1] == linear[j][0]: linear = [ linear[k] for k in range(len(linear)) if k not in (i, j) ] + [linear[i] + linear[j][1:]] linear_width = [ linear_width[k] for k in range(len(linear_width)) if k not in (i, j) ] + [max(linear_width[i], linear_width[j])] runway_parts_are_grouped = False break elif linear[i][-1] == linear[j][-1]: linear = [ linear[k] for k in range(len(linear)) if k not in (i, j) ] + [linear[i] + linear[j][-2::-1]] linear_width = [ linear_width[k] for k in range(len(linear_width)) if k not in (i, j) ] + [max(linear_width[i], linear_width[j])] runway_parts_are_grouped = False break elif linear[i][0] == linear[j][0]: linear = [ linear[k] for k in range(len(linear)) if k not in (i, j) ] + [linear[i][-1::-1] + linear[j][1:]] linear_width = [ linear_width[k] for k in range(len(linear_width)) if k not in (i, j) ] + [max(linear_width[i], linear_width[j])] runway_parts_are_grouped = False break elif linear[i][0] == linear[j][-1]: linear = [ linear[k] for k in range(len(linear)) if k not in (i, j) ] + [linear[j] + linear[i][1:]] linear_width = [ linear_width[k] for k in range(len(linear_width)) if k not in (i, j) ] + [max(linear_width[i], linear_width[j])] runway_parts_are_grouped = False break if not runway_parts_are_grouped: break ## Grow linear runways into rectangle ones and check wether they are duplicates of existing area ones, in which case they are skipped for (nodeid_list, width) in zip(linear, linear_width): runway_start = airport_layer.dicosmn[nodeid_list[0]] runway_end = airport_layer.dicosmn[nodeid_list[-1]] runway_length = GEO.dist(runway_start, runway_end) runway_start = numpy.round( numpy.array(runway_start) - numpy.array([tile.lon, tile.lat]), 7) runway_end = numpy.round( numpy.array(runway_end) - numpy.array([tile.lon, tile.lat]), 7) if width: width += 10 else: width = 30 + runway_length // 1000 pol = geometry.Polygon( VECT.buffer_simple_way( numpy.vstack((runway_start, runway_end)), width)) keep_this = True i = 0 for pol2 in runways_as_area: if (pol2[0].intersection(pol)).area > 0.6 * min( pol.area, pol2[0].area): # update area one with start end and width from linear one runways_as_area[i] = (pol2[0], runway_start, runway_end, width) # and then skip the linear one keep_this = False break i += 1 if keep_this: runways_as_line.append((pol, runway_start, runway_end, width)) ## Save this into the dico_airport dictionnary runway = VECT.ensure_MultiPolygon( ops.cascaded_union( [item[0] for item in runways_as_area + runways_as_line])) dico_airports[airport]['runway'] = (runway, runways_as_area, runways_as_line) return
def encode_runways_taxiways_and_aprons(tile, airport_layer, dico_airports, vector_map, patches_list): seeds = {'RUNWAY': [], 'TAXIWAY': [], 'APRON': []} total_rwy = 0 total_taxi = 0 for airport in dico_airports: if airport in patches_list: continue apt = dico_airports[airport] total_rwy += len(apt['runway'][1] + apt['runway'][2]) total_taxi += len(apt['taxiway'][1]) # First build the altitude generator function : that is a number of least square polynomial # approximations of altitudes along ways (runways, taxiways, etc). These will be used later # approriately weighted all together in order to give altitudes to any node in a runway or # taxiway (this weighting is highly important to avoid steppint effects close to intersections) alt_idx = index.Index() alt_dico = {} id = 0 for (runway_pol, runway_start, runway_end, runway_width) in apt['runway'][1] + apt['runway'][2]: center_way = numpy.vstack((runway_start, runway_end)) runway_length = VECT.length_in_meters(center_way) steps = int(max(runway_chunks, runway_length // 7)) (linestring, polyfit) = VECT.least_square_fit_altitude_along_way(center_way, steps, tile.dem, weights=True) #(linestring,polyfit)=VECT.spline_fit_altitude_along_way(center_way,steps,tile.dem)#,weights=True) alt_idx.insert(id, linestring.bounds) alt_dico[id] = (linestring, polyfit, runway_width) id += 1 for wayid in apt['taxiway'][1]: taxiway = numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([[tile.lon, tile.lat]]) taxiway_length = VECT.length_in_meters(taxiway) steps = int(max(runway_chunks, taxiway_length // 7)) (linestring, polyfit) = VECT.least_square_fit_altitude_along_way( taxiway, steps, tile.dem) #(linestring,polyfit)=VECT.spline_fit_altitude_along_way(taxiway,steps,tile.dem) alt_idx.insert(id, linestring.bounds) alt_dico[id] = (linestring, polyfit, 15) id += 1 # Now that alt_gen is filled, we may proceed to encoding pols = [ ] # we keep track of encoded pols to later plant seeds inside crossings etc ## First runways for (runway_pol, runway_start, runway_end, runway_width) in apt['runway'][1] + apt['runway'][2]: runway_length = VECT.length_in_meters( numpy.vstack((runway_start, runway_end))) refine_size = max(runway_length // runway_chunks, chunk_min_size) for pol in VECT.ensure_MultiPolygon(VECT.cut_to_tile(runway_pol)): way = numpy.round( VECT.refine_way(numpy.array(pol.exterior.coords), refine_size), 7) alti_way = numpy.array([ VECT.weighted_alt(node, alt_idx, alt_dico, tile.dem) for node in way ]).reshape((len(way), 1)) vector_map.insert_way(numpy.hstack([way, alti_way]), 'RUNWAY', check=True) pols.append(pol) for pol in pols: for subpol in VECT.ensure_MultiPolygon( pol.difference( ops.cascaded_union( [pol2 for pol2 in pols if pol2 != pol]))): seeds['RUNWAY'].append( numpy.array(subpol.representative_point())) for subpol in VECT.ensure_MultiPolygon( pol.intersection( ops.cascaded_union( [pol2 for pol2 in pols if pol2 != pol]))): seeds['RUNWAY'].append( numpy.array(subpol.representative_point())) ## Then taxiways ## Not sure if it is best to separate them from the runway or not... cleaned_taxiway_area = VECT.improved_buffer( apt['taxiway'][0].difference( VECT.improved_buffer(apt['runway'][0], 5, 0, 0).union( VECT.improved_buffer(apt['hangar'], 20, 0, 0))), 3, 2, 0.5) #cleaned_taxiway_area=VECT.improved_buffer(apt['taxiway'][0].difference(VECT.improved_buffer(apt['hangar'],20,0,0)),0,1,0.5) for pol in VECT.ensure_MultiPolygon( VECT.cut_to_tile(cleaned_taxiway_area)): if not pol.is_valid or pol.is_empty or pol.area < 1e-9: continue way = numpy.round(VECT.refine_way(numpy.array(pol.exterior), 20), 7) alti_way = numpy.array([ VECT.weighted_alt(node, alt_idx, alt_dico, tile.dem) for node in way ]).reshape((len(way), 1)) vector_map.insert_way(numpy.hstack([way, alti_way]), 'TAXIWAY', check=True) for subpol in pol.interiors: way = numpy.round(VECT.refine_way(numpy.array(subpol), 20), 7) alti_way = numpy.array([ VECT.weighted_alt(node, alt_idx, alt_dico, tile.dem) for node in way ]).reshape((len(way), 1)) vector_map.insert_way(numpy.hstack([way, alti_way]), 'TAXIWAY', check=True) seeds['TAXIWAY'].append(numpy.array(pol.representative_point())) ## Try to bring some aprons with, we are looking for the small ones along runways, you just need to add the 'include' tag to that apron in JOSM (local copy) for wayid in apt['apron'][1]: if wayid not in airport_layer.dicosmtags[ 'w'] or 'include' not in airport_layer.dicosmtags['w'][ wayid]: continue try: way = numpy.round( numpy.array([ airport_layer.dicosmn[nodeid] for nodeid in airport_layer.dicosmw[wayid] ]) - numpy.array([tile.lon, tile.lat]), 7) way = numpy.round(VECT.refine_way(way, 15), 7) apron_pol = geometry.Polygon(way) if not apron_pol.is_empty and runway_pol.is_valid: alti_way = numpy.array([ VECT.weighted_alt(node, alt_idx, alt_dico, tile.dem) for node in way ]).reshape((len(way), 1)) vector_map.insert_way(numpy.hstack([way, alti_way]), 'APRON', check=True) seeds['APRON'].append( numpy.array(apron_pol.representative_point())) except: pass for surface in ('RUNWAY', 'TAXIWAY', 'APRON'): if seeds[surface]: if surface in vector_map.seeds: vector_map.seeds[surface] += seeds[surface] else: vector_map.seeds[surface] = seeds[surface] plural_rwy = 's' if total_rwy > 1 else '' plural_taxi = 's' if total_taxi > 1 else '' UI.vprint(1, " Auto-patched", total_rwy, "runway" + plural_rwy + " and", total_taxi, "piece" + plural_taxi + " of taxiway.") return ops.cascaded_union([dico_airports[airport]['runway'][0] for airport in dico_airports]+\ [dico_airports[airport]['taxiway'][0] for airport in dico_airports]+\ [dico_airports[airport]['apron'][0] for airport in dico_airports])
def smooth_raster_over_airports(tile, dico_airports, preserve_boundary=True): max_pix = tile.apt_smoothing_pix for airport in dico_airports: if 'smoothing_pix' in dico_airports[airport]: try: max_pix = max(int(dico_airports[airport]['smoothing_pix']), max_pix) except: pass if not max_pix: tile.dem.write_to_file(FNAMES.alt_file(tile)) return if preserve_boundary: up = numpy.array(tile.dem.alt_dem[:max_pix]) down = numpy.array(tile.dem.alt_dem[-max_pix:]) left = numpy.array(tile.dem.alt_dem[:, :max_pix]) right = numpy.array(tile.dem.alt_dem[:, -max_pix:]) x0 = tile.dem.x0 x1 = tile.dem.x1 y0 = tile.dem.y0 y1 = tile.dem.y1 xstep = (x1 - x0) / tile.dem.nxdem ystep = (y1 - y0) / tile.dem.nydem upscale = max(ceil(ystep * GEO.lat_to_m / 10), 1) # target 10m of pixel size at most to avoiding aliasing for airport in dico_airports: try: pix = int(dico_airports[airport] ['smoothing_pix']) if 'smoothing_pix' in dico_airports[ airport] else tile.apt_smoothing_pix except: pix = tile.apt_smoothing_pix if not pix: continue (xmin, ymin, xmax, ymax) = dico_airports[airport]['boundary'].bounds colmin = max(floor((xmin - x0) / xstep) - pix, 0) colmax = min(ceil((xmax - x0) / xstep) + pix, tile.dem.nxdem - 1) rowmin = max(floor((y1 - ymax) / ystep) - pix, 0) rowmax = min(ceil((y1 - ymin) / ystep) + pix, tile.dem.nydem - 1) if colmin >= colmax or rowmin >= rowmax: continue X0 = x0 + colmin * xstep Y1 = y1 - rowmin * ystep airport_im = Image.new('L', (upscale * (colmax - colmin + 1), upscale * (rowmax - rowmin + 1))) airport_draw = ImageDraw.Draw(airport_im) full_area = VECT.ensure_MultiPolygon( ops.cascaded_union([ dico_airports[airport]['boundary'], dico_airports[airport]['runway'][0], dico_airports[airport]['hangar'], dico_airports[airport]['taxiway'][0], dico_airports[airport]['apron'][0] ])) for polygon in full_area: exterior_pol_pix = [(round(upscale * (X - X0) / xstep), round(upscale * (Y1 - Y) / ystep)) for (X, Y) in polygon.exterior.coords] airport_draw.polygon(exterior_pol_pix, fill='white') for inner_ring in polygon.interiors: interior_pol_pix = [(round(upscale * (X - X0) / xstep), round(upscale * (Y1 - Y) / ystep)) for (X, Y) in inner_ring.coords] airport_draw.polygon(interior_pol_pix, fill='black') airport_im = airport_im.resize( (colmax - colmin + 1, rowmax - rowmin + 1), Image.BICUBIC) tile.dem.alt_dem[rowmin:rowmax + 1, colmin:colmax + 1] = DEM.smoothen( tile.dem.alt_dem[rowmin:rowmax + 1, colmin:colmax + 1], pix, airport_im, preserve_boundary=False) if preserve_boundary: pix = max_pix for i in range(pix): tile.dem.alt_dem[i] = i / pix * tile.dem.alt_dem[i] + ( pix - i) / pix * up[i] tile.dem.alt_dem[-i - 1] = i / pix * tile.dem.alt_dem[-i - 1] + ( pix - i) / pix * down[-i - 1] for i in range(pix): tile.dem.alt_dem[:, i] = i / pix * tile.dem.alt_dem[:, i] + ( pix - i) / pix * left[:, i] tile.dem.alt_dem[:, -i - 1] = i / pix * tile.dem.alt_dem[:, -i - 1] + ( pix - i) / pix * right[:, -i - 1] tile.dem.write_to_file(FNAMES.alt_file(tile)) return
query += '"' + char + '"' else: query += char else: query = None if nargs in (7, 8): epsg_code = sys.argv[3] if nargs == 8: grid_size_or_bbox = eval(sys.argv[4]) else: grid_size = 0.02 if epsg_code == '4326' else 2000 pixel_size = float(sys.argv[nargs - 3]) buffer_width = float(sys.argv[nargs - 2]) / pixel_size mask_width = int(int(sys.argv[nargs - 1]) / pixel_size) pixel_size = pixel_size / 111120 if epsg_code == '4326' else pixel_size # assuming meters if not degrees vector_map = VECT.Vector_Map() osm_layer = OSM.OSM_layer() if not os.path.exists(cached_file_name): print("OSM query...") if not OSM.OSM_query_to_OSM_layer( query, '', osm_layer, cached_file_name=cached_file_name): print("OSM query failed. Exiting.") del (vector_map) time.sleep(1) sys.exit(0) else: print("Recycling OSM file...") osm_layer.update_dicosm(cached_file_name, None) print("Transform to multipolygon...") multipolygon_area = OSM.OSM_to_MultiPolygon(osm_layer, 0, 0) del (osm_layer)
def build_curv_tol_weight_map(tile, weight_array): if tile.apt_curv_tol != tile.curvature_tol: UI.vprint( 1, "-> Modifying curv_tol weight map according to runway locations.") airport_layer = OSM.OSM_layer() queries = [('rel["aeroway"="runway"]', 'rel["aeroway"="taxiway"]', 'rel["aeroway"="apron"]', 'way["aeroway"="runway"]', 'way["aeroway"="taxiway"]', 'way["aeroway"="apron"]')] tags_of_interest = ["all"] if not OSM.OSM_queries_to_OSM_layer(queries, airport_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='airports'): return 0 runway_network = OSM.OSM_to_MultiLineString(airport_layer, tile.lat, tile.lon) runway_area = VECT.improved_buffer(runway_network, 0.0003, 0.0001, 0.00001) if not runway_area: return 0 runway_area = VECT.ensure_MultiPolygon(runway_area) for polygon in runway_area.geoms if ( 'Multi' in runway_area.geom_type or 'Collection' in runway_area.geom_type) else [runway_area]: (xmin, ymin, xmax, ymax) = polygon.bounds x_shift = 1000 * tile.apt_curv_ext * GEO.m_to_lon(tile.lat) y_shift = 1000 * tile.apt_curv_ext * GEO.m_to_lat colmin = round((xmin - x_shift) * 1000) colmax = round((xmax + x_shift) * 1000) rowmax = round(((1 - ymin) + y_shift) * 1000) rowmin = round(((1 - ymax) - y_shift) * 1000) weight_array[ rowmin:rowmax + 1, colmin:colmax + 1] = tile.curvature_tol / tile.apt_curv_tol if tile.apt_curv_tol > 0 else 1 del (airport_layer) del (runway_network) del (runway_area) if tile.coast_curv_tol != tile.curvature_tol: UI.vprint( 1, "-> Modifying curv_tol weight map according to coastline location." ) sea_layer = OSM.OSM_layer() queries = ['way["natural"="coastline"]'] tags_of_interest = [] if not OSM.OSM_queries_to_OSM_layer(queries, sea_layer, tile.lat, tile.lon, tags_of_interest, cached_suffix='coastline'): return 0 for nodeid in sea_layer.dicosmn: (lonp, latp) = [float(x) for x in sea_layer.dicosmn[nodeid]] x_shift = 1000 * tile.coast_curv_ext * GEO.m_to_lon(tile.lat) y_shift = tile.coast_curv_ext / (111.12) colmin = round((lonp - tile.lon - x_shift) * 1000) colmax = round((lonp - tile.lon + x_shift) * 1000) rowmax = round((tile.lat + 1 - latp + y_shift) * 1000) rowmin = round((tile.lat + 1 - latp - y_shift) * 1000) weight_array[ rowmin:rowmax + 1, colmin:colmax + 1] = tile.curvature_tol / tile.coast_curv_tol if tile.coast_curv_tol > 0 else 1 del (sea_layer) # It could be of interest to write the weight file as a png for user editing #Image.fromarray((weight_array!=1).astype(numpy.uint8)*255).save('weight.png') return