Beispiel #1
0
def build_curv_tol_weight_map(tile, weight_array):
    if tile.apt_curv_tol != tile.curvature_tol and tile.apt_curv_tol > 0:
        UI.vprint(
            1,
            "-> Modifying curv_tol weight map according to runway locations.")
        try:
            f = open(FNAMES.apt_file(tile), 'rb')
            dico_airports = pickle.load(f)
            f.close()
        except:
            UI.vprint(
                1, "   WARNING: File", FNAMES.apt_file(tile),
                "is missing (erased after Step 1?), cannot check airport info for upgraded zoomlevel."
            )
            dico_airports = {}
        for airport in dico_airports:
            (xmin, ymin, xmax,
             ymax) = dico_airports[airport]['boundary'].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 = max(round((xmin - x_shift) * 1000), 0)
            colmax = min(round((xmax + x_shift) * 1000), 1000)
            rowmax = min(round(((1 - ymin) + y_shift) * 1000), 1000)
            rowmin = max(round(((1 - ymax) - y_shift) * 1000), 0)
            weight_array[rowmin:rowmax + 1, colmin:colmax +
                         1] = tile.curvature_tol / tile.apt_curv_tol
    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]]
            if lonp < tile.lon or lonp > tile.lon + 1 or latp < tile.lat or latp > tile.lat + 1:
                continue
            x_shift = 1000 * tile.coast_curv_ext * GEO.m_to_lon(tile.lat)
            y_shift = tile.coast_curv_ext / (111.12)
            colmin = max(round((lonp - tile.lon - x_shift) * 1000), 0)
            colmax = min(round((lonp - tile.lon + x_shift) * 1000), 1000)
            rowmax = min(round((tile.lat + 1 - latp + y_shift) * 1000), 1000)
            rowmin = max(round((tile.lat + 1 - latp - y_shift) * 1000), 0)
            weight_array[rowmin:rowmax + 1, colmin:colmax + 1] = numpy.maximum(
                weight_array[rowmin:rowmax + 1, colmin:colmax + 1],
                tile.curvature_tol / tile.coast_curv_tol)
        del (sea_layer)
    # It could be of interest to write the weight file as a png for user editing
    #from PIL import Image
    #Image.fromarray((weight_array!=1).astype(numpy.uint8)*255).save('weight.png')
    return
Beispiel #2
0
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]
Beispiel #3
0
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
Beispiel #4
0
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_airports(vector_map, tile):
    UI.vprint(0, "-> Dealing with airports")
    airport_layer = OSM.OSM_layer()
    queries = [('node["aeroway"]', 'way["aeroway"]', 'rel["aeroway"]')]
    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
    dico_airports = {}
    APT.discover_airport_names(airport_layer, dico_airports)
    APT.attach_surfaces_to_airports(airport_layer, dico_airports)
    APT.sort_and_reconstruct_runways(tile, airport_layer, dico_airports)
    APT.discard_unwanted_airports(tile, dico_airports)
    APT.build_hangar_areas(tile, airport_layer, dico_airports)
    APT.build_apron_areas(tile, airport_layer, dico_airports)
    APT.build_taxiway_areas(tile, airport_layer, dico_airports)
    APT.update_airport_boundaries(tile, dico_airports)
    APT.list_airports_and_runways(dico_airports)
    UI.vprint(1, "   Loading elevation data and smoothing it over airports.")
    tile.dem = DEM.DEM(tile.lat,
                       tile.lon,
                       tile.custom_dem,
                       tile.fill_nodata or "to zero",
                       info_only=False)
    APT.smooth_raster_over_airports(tile, dico_airports)
    (patches_area, patches_list) = include_patches(vector_map, tile)
    runway_taxiway_apron_area = APT.encode_runways_taxiways_and_aprons(
        tile, airport_layer, dico_airports, vector_map, patches_list)
    treated_area = ops.cascaded_union(
        [patches_area, runway_taxiway_apron_area])
    APT.encode_hangars(tile, dico_airports, vector_map, patches_list)
    APT.flatten_helipads(airport_layer, vector_map, tile, treated_area)
    #APT.encode_aprons(tile,dico_airports,vector_map)
    apt_array = APT.build_airport_array(tile, dico_airports)
    return (apt_array, treated_area)
Beispiel #6
0
         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)
 if not multipolygon_area.area:
Beispiel #7
0
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
Beispiel #8
0
def include_patches(vector_map, tile):
    UI.vprint(0, "-> Dealing with patches")
    patch_dir = FNAMES.patch_dir(tile.lat, tile.lon)
    if not os.path.exists(patch_dir):
        return geometry.Polygon()
    patch_layer = OSM.OSM_layer()
    for pfile_name in os.listdir(patch_dir):
        if pfile_name[-10:] != '.patch.osm':
            continue
        UI.vprint(1, "    " + pfile_name)
        try:
            patch_layer.update_dicosm(os.path.join(patch_dir, pfile_name),
                                      target_tags=None)
        except:
            UI.vprint(1, "     Error in treating", pfile_name, " , skipped.")
    dw = patch_layer.dicosmw
    dn = patch_layer.dicosmn
    df = patch_layer.dicosmfirst
    dt = patch_layer.dicosmtags
    patches_area = geometry.Polygon()

    def tanh_profile(alpha, x):
        return (numpy.tanh(
            (x - 0.5) * alpha) / numpy.tanh(0.5 * alpha) + 1) / 2

    def spline_profile(x):
        return 3 * x**2 - 2 * x**3

    def plane_profile(x):
        return x

    # reorganize them so that untagged dummy ways are treated last (due to altitude being first done kept for all)
    #waylist=list(set(dw).intersection(df['w']).intersection(dt['w']))+list(set(dw).intersection(df['w']).difference(dt['w']))
    waylist = list(set(df['w']).intersection(dt['w'])) + list(
        set(df['w']).difference(dt['w']))
    for wayid in waylist:
        way = numpy.array([dn[nodeid] for nodeid in dw[wayid]],
                          dtype=numpy.float)
        way = way - numpy.array([[tile.lon, tile.lat]])
        alti_way_orig = tile.dem.alt_vec(way)
        cplx_patch = False
        if wayid in dt['w']:
            wtags = dt['w'][wayid]
            if 'cst_alt_abs' in wtags:
                alti_way = numpy.ones(
                    (len(way), 1)) * float(wtags['cst_alt_abs'])
            elif 'cst_alt_rel' in wtags:
                alti_way = tile.dem.alt_vec_mean(way) + float(
                    wtags['cst_alt_rel'])
            elif 'var_alt_rel' in wtags:
                alti_way = alti_way_orig + float(wtags['var_alt_rel'])
            elif 'altitude' in wtags:  # deprecated : for backward compatibility only
                try:
                    alti_way = numpy.ones(
                        (len(way), 1)) * float(wtags['altitude'])
                except:
                    alti_way = tile.dem.alt_vec_mean(way)
            elif 'altitude_high' in wtags:
                cplx_patch = True
                if len(way) != 5 or (way[0] != way[-1]).all():
                    UI.vprint(
                        1,
                        "    Wrong number of nodes or non closed way for a altitude_high/altitude_low polygon, skipped."
                    )
                    continue
                short_high = way[-2:]
                short_low = way[1:3]
                try:
                    altitude_high = float(wtags['altitude_high'])
                    altitude_low = float(wtags['altitude_low'])
                except:
                    altitude_high = tile.dem.alt_vec(short_high).mean()
                    altitude_low = tile.dem.alt_vec(short_low).mean()
                try:
                    cell_size = float(wtags['cell_size'])
                except:
                    cell_size = 10
                try:
                    rnw_profile = wtags['profile']
                except:
                    rnw_profile = 'plane'
                try:
                    alpha = float(wtags['steepness'])
                except:
                    alpha = 2
                if 'tanh' in rnw_profile:
                    rnw_profile = lambda x: tanh_profile(alpha, x)
                elif rnw_profile == 'spline':
                    rnw_profile = spline_profile
                else:
                    rnw_profile = plane_profile
                rnw_vect = (short_high[0] + short_high[1] - short_low[0] -
                            short_low[1]) / 2
                rnw_length = sqrt(rnw_vect[0]**2 *
                                  cos(tile.lat * pi / 180)**2 +
                                  rnw_vect[1]**2) * 111120
                cuts_long = int(rnw_length / cell_size)
                if cuts_long:
                    cuts_long += 1
                    way=numpy.array([way[0]+i/cuts_long*(way[1]-way[0]) for i in range(cuts_long)]+\
                            [way[1]]+[way[2]+i/cuts_long*(way[3]-way[2]) for i in range(cuts_long)]+[way[3],way[4]])
                    alti_way = numpy.array([
                        altitude_high - rnw_profile(i / cuts_long) *
                        (altitude_high - altitude_low)
                        for i in range(cuts_long + 1)
                    ])
                    alti_way = numpy.hstack(
                        [alti_way, alti_way[::-1], alti_way[0]])
            else:
                alti_way = alti_way_orig
        else:
            alti_way = alti_way_orig
        if not cplx_patch:
            for i in range(len(way)):
                nodeid = dw[wayid][i]
                if nodeid in dt:
                    ntags = dt['n'][nodeid]
                    if 'alt_abs' in ntags:
                        alti_way[i] = float(ntags['alt_abs'])
                    elif 'alt_rel' in ntags:
                        alti_way[i] = alti_way_orig[i] + float(
                            ntags['alt_rel'])
        alti_way = alti_way.reshape((len(alti_way), 1))
        if (way[0] == way[-1]).all():
            try:
                pol = geometry.Polygon(way)
                if pol.is_valid and pol.area:
                    patches_area = patches_area.union(pol)
                    vector_map.insert_way(numpy.hstack([way, alti_way]),
                                          'INTERP_ALT',
                                          check=True)
                    seed = numpy.array(pol.representative_point())
                    if 'INTERP_ALT' in vector_map.seeds:
                        vector_map.seeds['INTERP_ALT'].append(seed)
                    else:
                        vector_map.seeds['INTERP_ALT'] = [seed]
                else:
                    UI.vprint(2, "Skipping invalid patch polygon.")
            except:
                UI.vprint(2, "Skipping invalid patch polygon.")
        else:
            vector_map.insert_way(numpy.hstack([way, alti_way]),
                                  'DUMMY',
                                  check=True)
    return patches_area
Beispiel #9
0
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 include_patches(vector_map, tile):
    def tanh_profile(alpha, x):
        return (numpy.tanh(
            (x - 0.5) * alpha) / numpy.tanh(0.5 * alpha) + 1) / 2

    def spline_profile(x):
        return 3 * x**2 - 2 * x**3

    def plane_profile(x):
        return x

    patches_list = []
    patches_area = geometry.Polygon()
    patch_dir = FNAMES.patch_dir(tile.lat, tile.lon)
    if not os.path.exists(patch_dir):
        return (patches_area, patches_list)
    for pfile_name in os.listdir(patch_dir):
        if pfile_name[-10:] != '.patch.osm':
            continue
        UI.vprint(1, "   Patching", pfile_name)
        patch_layer = OSM.OSM_layer()
        try:
            patch_layer.update_dicosm(os.path.join(patch_dir, pfile_name),
                                      input_tags=None,
                                      target_tags=None)
        except:
            UI.vprint(1, "     Error in treating", pfile_name, ", skipped.")
        patches_list.append(pfile_name[:-10])
        dw = patch_layer.dicosmw
        dn = patch_layer.dicosmn
        df = patch_layer.dicosmfirst
        dt = patch_layer.dicosmtags
        patches_area = geometry.Polygon()
        # reorganize them so that untagged dummy ways are treated last (due to altitude being first done kept for all)
        #waylist=list(set(dw).intersection(df['w']).intersection(dt['w']))+list(set(dw).intersection(df['w']).difference(dt['w']))
        #HACK
        waylist = tuple(df['w'].intersection(dt['w'])) + tuple(
            df['w'].difference(dt['w']))
        for wayid in waylist:
            way = numpy.array([dn[nodeid] for nodeid in dw[wayid]],
                              dtype=numpy.float)
            way = way - numpy.array([[tile.lon, tile.lat]])
            alti_way_orig = tile.dem.alt_vec(way)
            cplx_way = False
            if wayid in dt['w']:
                wtags = dt['w'][wayid]
                if 'cst_alt_abs' in wtags:
                    alti_way = numpy.ones(
                        (len(way), 1)) * float(wtags['cst_alt_abs'])
                elif 'cst_alt_rel' in wtags:
                    alti_way = numpy.ones(
                        (len(way), 1)) * (numpy.mean(tile.dem.alt_vec(way)) +
                                          float(wtags['cst_alt_rel']))
                elif 'var_alt_rel' in wtags:
                    alti_way = alti_way_orig + float(wtags['var_alt_rel'])
                elif 'altitude' in wtags:  # deprecated : for backward compatibility only
                    try:
                        alti_way = numpy.ones(
                            (len(way), 1)) * float(wtags['altitude'])
                    except:
                        alti_way = numpy.ones(
                            (len(way), 1)) * numpy.mean(tile.dem.alt_vec(way))
                elif 'altitude_high' in wtags:
                    cplx_way = True
                    if len(way) != 5 or (way[0] != way[-1]).all():
                        UI.vprint(
                            1,
                            "    Wrong number of nodes or non closed way for a altitude_high/altitude_low polygon, skipped."
                        )
                        continue
                    short_high = way[-2:]
                    short_low = way[1:3]
                    try:
                        altitude_high = float(wtags['altitude_high'])
                        altitude_low = float(wtags['altitude_low'])
                    except:
                        altitude_high = tile.dem.alt_vec(short_high).mean()
                        altitude_low = tile.dem.alt_vec(short_low).mean()
                    try:
                        cell_size = float(wtags['cell_size'])
                    except:
                        cell_size = 10
                    try:
                        rnw_profile = wtags['profile']
                    except:
                        rnw_profile = 'plane'
                    try:
                        alpha = float(wtags['steepness'])
                    except:
                        alpha = 2
                    if 'tanh' in rnw_profile:
                        rnw_profile = lambda x: tanh_profile(alpha, x)
                    elif rnw_profile == 'spline':
                        rnw_profile = spline_profile
                    else:
                        rnw_profile = plane_profile
                    rnw_vect = (short_high[0] + short_high[1] - short_low[0] -
                                short_low[1]) / 2
                    rnw_length = sqrt(rnw_vect[0]**2 *
                                      cos(tile.lat * pi / 180)**2 +
                                      rnw_vect[1]**2) * 111120
                    cuts_long = int(rnw_length / cell_size)
                    if cuts_long:
                        cuts_long += 1
                        way=numpy.array([way[0]+i/cuts_long*(way[1]-way[0]) for i in range(cuts_long)]+\
                                [way[1]]+[way[2]+i/cuts_long*(way[3]-way[2]) for i in range(cuts_long)]+[way[3],way[4]])
                        alti_way = numpy.array([
                            altitude_high - rnw_profile(i / cuts_long) *
                            (altitude_high - altitude_low)
                            for i in range(cuts_long + 1)
                        ])
                        alti_way = numpy.hstack(
                            [alti_way, alti_way[::-1], alti_way[0]])
                else:
                    alti_way = alti_way_orig
            else:
                alti_way = alti_way_orig
            if not cplx_way:
                for i in range(len(way)):
                    nodeid = dw[wayid][i]
                    if nodeid in dt['n']:
                        ntags = dt['n'][nodeid]
                        if 'alt_abs' in ntags:
                            alti_way[i] = float(ntags['alt_abs'])
                        elif 'alt_rel' in ntags:
                            alti_way[i] = alti_way_orig[i] + float(
                                ntags['alt_rel'])
            alti_way = alti_way.reshape((len(alti_way), 1))
            if (way[0] == way[-1]).all():
                try:
                    pol = geometry.Polygon(way)
                    if pol.is_valid and pol.area:
                        patches_area = patches_area.union(pol)
                        vector_map.insert_way(numpy.hstack([way, alti_way]),
                                              'INTERP_ALT',
                                              check=True)
                        seed = numpy.array(pol.representative_point())
                        if 'INTERP_ALT' in vector_map.seeds:
                            vector_map.seeds['INTERP_ALT'].append(seed)
                        else:
                            vector_map.seeds['INTERP_ALT'] = [seed]
                        if cplx_way and cuts_long:
                            for i in range(1, cuts_long):
                                id0 = vector_map.dico_nodes[tuple(way[i])]
                                id1 = vector_map.dico_nodes[tuple(way[-2 - i])]
                                vector_map.insert_edge(
                                    id0, id1,
                                    vector_map.dico_attributes['DUMMY'])
                    else:
                        UI.vprint(2, "     Skipping invalid patch polygon.")
                except:
                    UI.vprint(2, "     Skipping invalid patch polygon.")
            else:
                vector_map.insert_way(numpy.hstack([way, alti_way]),
                                      'DUMMY',
                                      check=True)
    for pdir_name in os.listdir(patch_dir):
        if not os.path.isdir(os.path.join(patch_dir, pdir_name)): continue
        UI.vprint(1, "   Including OBJ8 objects from", pdir_name)
        patches_list.append(pdir_name)
        for pfile_name in os.listdir(os.path.join(patch_dir, pdir_name)):
            pfile_namelong = os.path.join(patch_dir, pdir_name, pfile_name)
            try:
                pfile = open(pfile_namelong, "r")
            except:
                continue
            firstline = pfile.readline()
            if not 'ANCHOR' in firstline:
                UI.vprint(
                    1, "     Object ", pfile_name,
                    " is missing and ANCHOR in first line, skipping it.")
                continue
            pfile.close()
            try:
                (lon_anchor, lat_anchor, alt_anchor,
                 heading_anchor) = [float(x) for x in firstline.split()[1:]]
            except:
                try:
                    (lon_anchor, lat_anchor, heading_anchor) = [
                        float(x) for x in firstline.split()[1:]
                    ]
                    alt_anchor = tile.dem.alt(
                        (lon_anchor - tile.lon, lat_anchor - tile.lat))
                except:
                    UI.vprint(1, "     Anchor wrongly encode for : ",
                              pfile_name, " skipping that one.")
                    continue
            patches_area = patches_area.union(
                keep_obj8(lat_anchor, lon_anchor, alt_anchor, heading_anchor,
                          pfile_namelong, vector_map, tile))
    return (patches_area, patches_list)
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 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
Beispiel #13
0
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