def create_terrain_file(tile, texture_file_name, til_x_left, til_y_top, zoomlevel, provider_code, tri_type, is_overlay): if not os.path.exists(os.path.join(tile.build_dir, 'terrain')): os.makedirs(os.path.join(tile.build_dir, 'terrain')) suffix = '_water' if tri_type == 1 else '_sea' if tri_type == 2 else '' if is_overlay: suffix += '_overlay' ter_file_name = texture_file_name[:-4] + suffix + '.ter' if use_test_texture: texture_file_name = 'test_texture.dds' with open(os.path.join(tile.build_dir, 'terrain', ter_file_name), 'w') as f: f.write('A\n800\nTERRAIN\n\n') [lat_med, lon_med] = GEO.gtile_to_wgs84(til_x_left + 8, til_y_top + 8, zoomlevel) texture_approx_size = int( GEO.webmercator_pixel_size(lat_med, zoomlevel) * 4096) f.write('LOAD_CENTER '+'{:.5f}'.format(lat_med)+' '\ +'{:.5f}'.format(lon_med)+' '\ +str(texture_approx_size)+' 4096\n') f.write('BASE_TEX_NOWRAP ../textures/' + texture_file_name + '\n') if tri_type in (1, 2) and not is_overlay: # experimental water f.write('TEXTURE_NORMAL ' + str(2**(17 - zoomlevel)) + ' ../textures/water_normal_map.dds\n') f.write('GLOBAL_specular 1.0\n') f.write('NORMAL_METALNESS\n') if not os.path.exists( os.path.join(tile.build_dir, 'textures', 'water_normal_map.dds')): shutil.copy( os.path.join(FNAMES.Utils_dir, 'water_normal_map.dds'), os.path.join(tile.build_dir, 'textures')) elif tri_type == 1 or (tri_type == 2 and is_overlay == 'ratio_water'): #constant transparency level f.write('BORDER_TEX ../textures/water_transition.png\n') if not os.path.exists( os.path.join(tile.build_dir, 'textures', 'water_transition.png')): shutil.copy( os.path.join(FNAMES.Utils_dir, 'water_transition.png'), os.path.join(tile.build_dir, 'textures')) elif tri_type == 2: #border_tex mask f.write('LOAD_CENTER_BORDER '+'{:.5f}'.format(lat_med)+' '\ +'{:.5f}'.format(lon_med)+' '+str(texture_approx_size)+' '+str(4096//2**(zoomlevel-tile.mask_zl))+'\n') f.write('BORDER_TEX ../textures/' + FNAMES.mask_file( til_x_left, til_y_top, zoomlevel, provider_code) + '\n') elif tile.use_decal_on_terrain: f.write('DECAL_LIB lib/g10/decals/maquify_1_green_key.dcl\n') if tri_type in (1, 2): f.write('WET\n') if tri_type in (1, 2) or not tile.terrain_casts_shadows: f.write('NO_SHADOW\n') return ter_file_name
def build_masks(tile): ########################################## def transition_profile(ratio, ttype): if ttype == 'spline': return 3 * ratio**2 - 2 * ratio**3 elif ttype == 'linear': return ratio elif ttype == 'parabolic': return 2 * ratio - ratio**2 ########################################## UI.red_flag = False UI.logprint("Step 2.5 for tile lat=", tile.lat, ", lon=", tile.lon, ": starting.") UI.vprint( 0, "\nStep 2.5 : Building masks for tile " + FNAMES.short_latlon(tile.lat, tile.lon) + " : \n--------\n") timer = time.time() if not os.path.exists(FNAMES.mesh_file(tile.build_dir, tile.lat, tile.lon)): UI.lvprint(0, "ERROR: Mesh file ", FNAMES.mesh_file(tile.build_dir, tile.lat, tile.lon), "absent.") UI.exit_message_and_bottom_line('') return 0 if not os.path.exists(FNAMES.mask_dir(tile.lat, tile.lon)): os.makedirs(FNAMES.mask_dir(tile.lat, tile.lon)) mesh_file_name_list = [] for close_lat in range(tile.lat - 1, tile.lat + 2): for close_lon in range(tile.lon - 1, tile.lon + 2): close_build_dir = tile.build_dir if tile.grouped else tile.build_dir.replace( FNAMES.tile_dir(tile.lat, tile.lon), FNAMES.tile_dir(close_lat, close_lon)) close_mesh_file_name = FNAMES.mesh_file(close_build_dir, close_lat, close_lon) if os.path.isfile(close_mesh_file_name): mesh_file_name_list.append(close_mesh_file_name) #################### dico_masks = {} dico_masks_inland = {} #################### [til_x_min, til_y_min] = GEO.wgs84_to_orthogrid(tile.lat + 1, tile.lon, tile.mask_zl) [til_x_max, til_y_max] = GEO.wgs84_to_orthogrid(tile.lat, tile.lon + 1, tile.mask_zl) UI.vprint(1, "-> Deleting existing masks") 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): try: os.remove( os.path.join(FNAMES.mask_dir(tile.lat, tile.lon), FNAMES.legacy_mask(til_x, til_y))) except: pass UI.vprint(1, "-> Reading mesh data") for mesh_file_name in mesh_file_name_list: try: f_mesh = open(mesh_file_name, "r") UI.vprint(1, " * ", mesh_file_name) except: UI.lvprint(1, "Mesh file ", mesh_file_name, " could not be read. Skipped.") continue for i in range(0, 4): f_mesh.readline() nbr_pt_in = int(f_mesh.readline()) pt_in = numpy.zeros(5 * nbr_pt_in, 'float') for i in range(0, nbr_pt_in): pt_in[5 * i:5 * i + 3] = [float(x) for x in f_mesh.readline().split()[:3]] for i in range(0, 3): f_mesh.readline() for i in range(0, nbr_pt_in): pt_in[5 * i + 3:5 * i + 5] = [float(x) for x in f_mesh.readline().split()[:2]] for i in range(0, 2): # skip 2 lines f_mesh.readline() nbr_tri_in = int(f_mesh.readline()) # read nbr of tris step_stones = nbr_tri_in // 100 percent = -1 UI.vprint( 2, " Attribution process of masks buffers to water triangles for " + str(mesh_file_name) + ".") for i in range(0, nbr_tri_in): if i % step_stones == 0: percent += 1 UI.progress_bar(1, int(percent * 5 / 10)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 (n1, n2, n3, tri_type) = [int(x) - 1 for x in f_mesh.readline().split()[:4]] tri_type += 1 tri_type = (tri_type & 2) or (tri_type & 1) if (not tri_type) or (tri_type == 1 and not tile.use_masks_for_inland): continue (lon1, lat1) = pt_in[5 * n1:5 * n1 + 2] (lon2, lat2) = pt_in[5 * n2:5 * n2 + 2] (lon3, lat3) = pt_in[5 * n3:5 * n3 + 2] bary_lat = (lat1 + lat2 + lat3) / 3 bary_lon = (lon1 + lon2 + lon3) / 3 (til_x, til_y) = GEO.wgs84_to_orthogrid(bary_lat, bary_lon, tile.mask_zl) if til_x < til_x_min - 16 or til_x > til_x_max + 16 or til_y < til_y_min - 16 or til_y > til_y_max + 16: continue (til_x2, til_y2) = GEO.wgs84_to_orthogrid(bary_lat, bary_lon, tile.mask_zl + 2) a = (til_x2 // 16) % 4 b = (til_y2 // 16) % 4 if (til_x, til_y) in dico_masks: dico_masks[(til_x, til_y)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x, til_y)] = [(lat1, lon1, lat2, lon2, lat3, lon3)] if a == 0: if (til_x - 16, til_y) in dico_masks: dico_masks[(til_x - 16, til_y)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x - 16, til_y)] = [(lat1, lon1, lat2, lon2, lat3, lon3)] if b == 0: if (til_x - 16, til_y - 16) in dico_masks: dico_masks[(til_x - 16, til_y - 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x - 16, til_y - 16)] = [ (lat1, lon1, lat2, lon2, lat3, lon3) ] elif b == 3: if (til_x - 16, til_y + 16) in dico_masks: dico_masks[(til_x - 16, til_y + 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x - 16, til_y + 16)] = [ (lat1, lon1, lat2, lon2, lat3, lon3) ] elif a == 3: if (til_x + 16, til_y) in dico_masks: dico_masks[(til_x + 16, til_y)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x + 16, til_y)] = [(lat1, lon1, lat2, lon2, lat3, lon3)] if b == 0: if (til_x + 16, til_y - 16) in dico_masks: dico_masks[(til_x + 16, til_y - 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x + 16, til_y - 16)] = [ (lat1, lon1, lat2, lon2, lat3, lon3) ] elif b == 3: if (til_x + 16, til_y + 16) in dico_masks: dico_masks[(til_x + 16, til_y + 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x + 16, til_y + 16)] = [ (lat1, lon1, lat2, lon2, lat3, lon3) ] if b == 0: if (til_x, til_y - 16) in dico_masks: dico_masks[(til_x, til_y - 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x, til_y - 16)] = [(lat1, lon1, lat2, lon2, lat3, lon3)] elif b == 3: if (til_x, til_y + 16) in dico_masks: dico_masks[(til_x, til_y + 16)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks[(til_x, til_y + 16)] = [(lat1, lon1, lat2, lon2, lat3, lon3)] f_mesh.close() if not tile.use_masks_for_inland: UI.vprint(2, " Taking care of inland water near shoreline") f_mesh = open(mesh_file_name, "r") for i in range(0, 4): f_mesh.readline() nbr_pt_in = int(f_mesh.readline()) for i in range(0, 2 * nbr_pt_in + 5): f_mesh.readline() nbr_tri_in = int(f_mesh.readline()) # read nbr of tris step_stones = nbr_tri_in // 100 percent = -1 for i in range(0, nbr_tri_in): if i % step_stones == 0: percent += 1 UI.progress_bar(1, int(percent * 5 / 10)) if UI.red_flag: UI.exit_message_and_bottom_line() return 0 (n1, n2, n3, tri_type) = [ int(x) - 1 for x in f_mesh.readline().split()[:4] ] tri_type += 1 tri_type = (tri_type & 2) or (tri_type & 1) if not (tri_type == 1): continue (lon1, lat1) = pt_in[5 * n1:5 * n1 + 2] (lon2, lat2) = pt_in[5 * n2:5 * n2 + 2] (lon3, lat3) = pt_in[5 * n3:5 * n3 + 2] bary_lat = (lat1 + lat2 + lat3) / 3 bary_lon = (lon1 + lon2 + lon3) / 3 (til_x, til_y) = GEO.wgs84_to_orthogrid(bary_lat, bary_lon, tile.mask_zl) if til_x < til_x_min - 16 or til_x > til_x_max + 16 or til_y < til_y_min - 16 or til_y > til_y_max + 16: continue (til_x2, til_y2) = GEO.wgs84_to_orthogrid(bary_lat, bary_lon, tile.mask_zl + 2) a = (til_x2 // 16) % 4 b = (til_y2 // 16) % 4 # Here an inland water tri is added ONLY if sea water tri were already added for this mask extent if (til_x, til_y) in dico_masks: if (til_x, til_y) in dico_masks_inland: dico_masks_inland[(til_x, til_y)].append( (lat1, lon1, lat2, lon2, lat3, lon3)) else: dico_masks_inland[(til_x, til_y)] = [ (lat1, lon1, lat2, lon2, lat3, lon3) ] f_mesh.close() UI.vprint(1, "-> Construction of the masks") if tile.masks_use_DEM_too: tile.ensure_elevation_data() task_len = len(dico_masks) task_done = 0 for (til_x, til_y) in dico_masks: if UI.red_flag: UI.exit_message_and_bottom_line() return 0 task_done += 1 UI.progress_bar(1, 50 + int(49 * task_done / task_len)) if til_x < til_x_min or til_x > til_x_max or til_y < til_y_min or til_y > til_y_max: continue (latm0, lonm0) = GEO.gtile_to_wgs84(til_x, til_y, tile.mask_zl) (px0, py0) = GEO.wgs84_to_pix(latm0, lonm0, tile.mask_zl) px0 -= 1024 py0 -= 1024 # 1) We start with a black mask mask_im = Image.new("L", (4096 + 2 * 1024, 4096 + 2 * 1024), 'black') mask_draw = ImageDraw.Draw(mask_im) # 2) We fill it with white over the extent of each tile around for which we had a mesh available for mesh_file_name in mesh_file_name_list: latlonstr = mesh_file_name.split('.mes')[-2][-7:] lathere = int(latlonstr[0:3]) lonhere = int(latlonstr[3:7]) (px1, py1) = GEO.wgs84_to_pix(lathere, lonhere, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lathere, lonhere + 1, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lathere + 1, lonhere + 1, tile.mask_zl) (px4, py4) = GEO.wgs84_to_pix(lathere + 1, lonhere, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 px4 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 py4 -= py0 mask_draw.polygon([(px1, py1), (px2, py2), (px3, py3), (px4, py4)], fill='white') # 3a) We overwrite the withe part of the mask with grey (ratio_water dependent) where inland water was detected in the first part above if (til_x, til_y) in dico_masks_inland: for (lat1, lon1, lat2, lon2, lat3, lon3) in dico_masks_inland[(til_x, til_y)]: (px1, py1) = GEO.wgs84_to_pix(lat1, lon1, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lat2, lon2, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lat3, lon3, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 mask_draw.polygon([(px1, py1), (px2, py2), (px3, py3)], fill=int(255 * (1 - tile.ratio_water))) # 3b) We overwrite the withe + grey part of the mask with black where sea water was detected in the first part above for (lat1, lon1, lat2, lon2, lat3, lon3) in dico_masks[(til_x, til_y)]: (px1, py1) = GEO.wgs84_to_pix(lat1, lon1, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lat2, lon2, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lat3, lon3, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 mask_draw.polygon([(px1, py1), (px2, py2), (px3, py3)], fill='black') del (mask_draw) #mask_im=mask_im.convert("L") img_array = numpy.array(mask_im, dtype=numpy.uint8) if tile.masks_use_DEM_too: #computing the part of the mask coming from the DEM: (latmax, lonmin) = GEO.pix_to_wgs84(px0, py0, tile.mask_zl) (latmin, lonmax) = GEO.pix_to_wgs84(px0 + 6144, py0 + 6144, tile.mask_zl) (x03857, y03857) = GEO.transform('4326', '3857', lonmin, latmax) (x13857, y13857) = GEO.transform('4326', '3857', lonmax, latmin) ((lonmin, lonmax, latmin, latmax), demarr4326) = tile.dem.super_level_set( 1, (lonmin, lonmax, latmin, latmax)) if demarr4326.any(): demim4326 = Image.fromarray( demarr4326.astype(numpy.uint8) * 255) del (demarr4326) s_bbox = (lonmin, latmax, lonmax, latmin) t_bbox = (x03857, y03857, x13857, y13857) demim3857 = IMG.gdalwarp_alternative(s_bbox, '4326', demim4326, t_bbox, '3857', (6144, 6144)) demim3857 = demim3857.filter( ImageFilter.GaussianBlur( 0.3 * 2**(tile.mask_zl - 14))) # slight increase of area dem_array = (numpy.array(demim3857, dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 del (demim3857) del (demim4326) img_array = numpy.maximum(img_array, dem_array) custom_mask_array = numpy.zeros((4096, 4096), dtype=numpy.uint8) if tile.masks_custom_extent: (latm1, lonm1) = GEO.gtile_to_wgs84(til_x + 16, til_y + 16, tile.mask_zl) bbox_4326 = (lonm0, latm0, lonm1, latm1) masks_im = IMG.has_data(bbox_4326, tile.masks_extent_code, True, mask_size=(4096, 4096), is_sharp_resize=False, is_mask_layer=False) if masks_im: custom_mask_array = (numpy.array(masks_im, dtype=numpy.uint8) * tile.ratio_water).astype(numpy.uint8) if (img_array.max() == 0) and ( custom_mask_array.max() == 0 ): # no need to test if the mask is all white since it would otherwise not be present in dico_mask UI.vprint(1, " Skipping", FNAMES.legacy_mask(til_x, til_y)) continue else: UI.vprint(1, " Creating", FNAMES.legacy_mask(til_x, til_y)) # Blur of the mask pxscal = GEO.webmercator_pixel_size(tile.lat + 0.5, tile.mask_zl) if tile.masking_mode == "sand": blur_width = int(tile.masks_width / pxscal) elif tile.masking_mode == "rocks": blur_width = tile.masks_width / pxscal elif tile.masking_mode == "3steps": blur_width = [L / pxscal for L in tile.masks_width] if tile.masking_mode == "sand" and blur_width: # convolution with a hat function b_img_array = numpy.array(img_array) kernel = numpy.array(range(1, 2 * blur_width)) kernel[blur_width:] = range(blur_width - 1, 0, -1) kernel = kernel / blur_width**2 for i in range(0, len(b_img_array)): b_img_array[i] = numpy.convolve(b_img_array[i], kernel, 'same') b_img_array = b_img_array.transpose() for i in range(0, len(b_img_array)): b_img_array[i] = numpy.convolve(b_img_array[i], kernel, 'same') b_img_array = b_img_array.transpose() b_img_array = 2 * numpy.minimum(b_img_array, 127) b_img_array = numpy.array(b_img_array, dtype=numpy.uint8) elif tile.masking_mode == "rocks" and blur_width: # slight increase of the mask, then gaussian blur, nonlinear map and a tiny bit of smoothing again on a short scale along the shore b_img_array=(numpy.array(Image.fromarray(img_array).convert("L").\ filter(ImageFilter.GaussianBlur(blur_width/1.7)),dtype=numpy.uint8)>0).astype(numpy.uint8)*255 #blur it b_img_array=numpy.array(Image.fromarray(b_img_array).convert("L").\ filter(ImageFilter.GaussianBlur(blur_width)),dtype=numpy.uint8) #nonlinear transform to make the transition quicker at the shore (gaussian is too flat) gamma = 2.5 b_img_array=(((numpy.tan((b_img_array.astype(numpy.float32)-127.5)/128*atan(3))-numpy.tan(-127.5/128*atan(3)))\ *254/(2*numpy.tan(127.5/128*atan(3))))**gamma/(255**(gamma-1))).astype(numpy.uint8) #b_img_array=numpy.minimum(b_img_array,200) #still some slight smoothing at the shore b_img_array=numpy.maximum(b_img_array,numpy.array(Image.fromarray(img_array).convert("L").\ filter(ImageFilter.GaussianBlur(2**(tile.mask_zl-14))),dtype=numpy.uint8)) elif tile.masking_mode == "3steps": # why trying something so complicated... transin = blur_width[0] midzone = blur_width[1] transout = blur_width[2] shore_level = 255 sea_level = int(tile.ratio_water * 255) b_img_array = b_mask_array = numpy.array(img_array) # First the transition at the shore # We go from shore_level to sea_level in transin meters stepsin = int(transin / 3) for i in range(stepsin): value = shore_level + transition_profile( (i + 1) / stepsin, 'parabolic') * (sea_level - shore_level) b_mask_array=(numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(1)),dtype=numpy.uint8)>0).astype(numpy.uint8)*255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = value UI.vprint(2, value) # Next the intermediate zone at constant transparency sea_b_radius = midzone / 3 sea_b_radius_buffered = (midzone + transout) / 2 b_mask_array=(numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(sea_b_radius_buffered)),dtype=numpy.uint8)>0).astype(numpy.uint8)*255 b_mask_array=(numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(sea_b_radius_buffered-sea_b_radius)),dtype=numpy.uint8)==255).astype(numpy.uint8)*255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = sea_level # Finally the transition to the X-Plane sea # We go from sea_level to 0 in transout meters stepsout = int(transout / 3) for i in range(stepsout): value = sea_level * (1 - transition_profile( (i + 1) / stepsout, 'linear')) b_mask_array=(numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(1)),dtype=numpy.uint8)>0).astype(numpy.uint8)*255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = value UI.vprint(2, value) # To smoothen the thresolding introduced above we do a global short extent gaussian blur b_img_array=numpy.array(Image.fromarray(b_img_array).convert("L").\ filter(ImageFilter.GaussianBlur(2)),dtype=numpy.uint8) else: # Just a (futile) copy b_img_array = numpy.array(img_array) # Ensure land is kept to 255 on the mask to avoid unecessary ones, crop to final size, and take the # max with the possible custom extent mask img_array = numpy.maximum(img_array, b_img_array)[1024:4096 + 1024, 1024:4096 + 1024] img_array = numpy.maximum(img_array, custom_mask_array) if not (img_array.max() == 0 or img_array.min() == 255): masks_im = Image.fromarray( img_array) #.filter(ImageFilter.GaussianBlur(3)) masks_im.save( os.path.join(FNAMES.mask_dir(tile.lat, tile.lon), FNAMES.legacy_mask(til_x, til_y))) UI.vprint(2, " Done.") else: UI.vprint(1, " Ends-up being discarded.") UI.progress_bar(1, 100) UI.timings_and_bottom_line(timer) UI.logprint("Step 2.5 for tile lat=", tile.lat, ", lon=", tile.lon, ": normal exit.") return
def build_mask(til_x, til_y): if til_x < til_x_min or til_x > til_x_max or til_y < til_y_min or til_y > til_y_max: return 1 (latm0, lonm0) = GEO.gtile_to_wgs84(til_x, til_y, tile.mask_zl) (px0, py0) = GEO.wgs84_to_pix(latm0, lonm0, tile.mask_zl) px0 -= 1024 py0 -= 1024 # 1) We start with a black mask mask_im = Image.new("L", (4096 + 2 * 1024, 4096 + 2 * 1024), 'black') mask_draw = ImageDraw.Draw(mask_im) # 2) We fill it with white over the extent of each tile around for which we had a mesh available for mesh_file_name in mesh_file_name_list: latlonstr = mesh_file_name.split('.mes')[-2][-7:] lathere = int(latlonstr[0:3]) lonhere = int(latlonstr[3:7]) (px1, py1) = GEO.wgs84_to_pix(lathere, lonhere, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lathere, lonhere + 1, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lathere + 1, lonhere + 1, tile.mask_zl) (px4, py4) = GEO.wgs84_to_pix(lathere + 1, lonhere, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 px4 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 py4 -= py0 mask_draw.polygon([(px1, py1), (px2, py2), (px3, py3), (px4, py4)], fill='white') # 3a) We overwrite the white part of the mask with grey (ratio_water dependent) where inland water was detected in the first part above if (til_x, til_y) in dico_masks_inland: for (lat1, lon1, lat2, lon2, lat3, lon3) in dico_masks_inland[(til_x, til_y)]: (px1, py1) = GEO.wgs84_to_pix(lat1, lon1, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lat2, lon2, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lat3, lon3, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 mask_draw.polygon( [(px1, py1), (px2, py2), (px3, py3)], fill=sea_level) # int(255*(1-tile.ratio_water))) # 3b) We overwrite the white + grey part of the mask with black where sea water was detected in the first part above for (lat1, lon1, lat2, lon2, lat3, lon3) in dico_masks[(til_x, til_y)]: (px1, py1) = GEO.wgs84_to_pix(lat1, lon1, tile.mask_zl) (px2, py2) = GEO.wgs84_to_pix(lat2, lon2, tile.mask_zl) (px3, py3) = GEO.wgs84_to_pix(lat3, lon3, tile.mask_zl) px1 -= px0 px2 -= px0 px3 -= px0 py1 -= py0 py2 -= py0 py3 -= py0 mask_draw.polygon([(px1, py1), (px2, py2), (px3, py3)], fill='black') del (mask_draw) # mask_im=mask_im.convert("L") img_array = numpy.array(mask_im, dtype=numpy.uint8) if tile.masks_use_DEM_too: # computing the part of the mask coming from the DEM: (latmax, lonmin) = GEO.pix_to_wgs84(px0, py0, tile.mask_zl) (latmin, lonmax) = GEO.pix_to_wgs84(px0 + 6144, py0 + 6144, tile.mask_zl) (x03857, y03857) = GEO.transform('4326', '3857', lonmin, latmax) (x13857, y13857) = GEO.transform('4326', '3857', lonmax, latmin) ((lonmin, lonmax, latmin, latmax), demarr4326) = tile.dem.super_level_set( mask_altitude_above, (lonmin, lonmax, latmin, latmax)) if demarr4326.any(): demim4326 = Image.fromarray( demarr4326.astype(numpy.uint8) * 255) del (demarr4326) s_bbox = (lonmin, latmax, lonmax, latmin) t_bbox = (x03857, y03857, x13857, y13857) demim3857 = IMG.gdalwarp_alternative(s_bbox, '4326', demim4326, t_bbox, '3857', (6144, 6144)) demim3857 = demim3857.filter( ImageFilter.GaussianBlur( 0.3 * 2**(tile.mask_zl - 14))) # slight increase of area dem_array = (numpy.array(demim3857, dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 del (demim3857) del (demim4326) img_array = numpy.maximum(img_array, dem_array) custom_mask_array = numpy.zeros((4096, 4096), dtype=numpy.uint8) if tile.masks_custom_extent: (latm1, lonm1) = GEO.gtile_to_wgs84(til_x + 16, til_y + 16, tile.mask_zl) bbox_4326 = (lonm0, latm0, lonm1, latm1) masks_im = IMG.has_data(bbox_4326, tile.masks_custom_extent, True, mask_size=(4096, 4096), is_sharp_resize=False, is_mask_layer=False) if masks_im: custom_mask_array = (numpy.array(masks_im, dtype=numpy.uint8) * (sea_level / 255)).astype(numpy.uint8) if (img_array.max() == 0) and ( custom_mask_array.max() == 0 ): # no need to test if the mask is all white since it would otherwise not be present in dico_mask UI.vprint(1, " Skipping", FNAMES.legacy_mask(til_x, til_y)) return 1 else: UI.vprint(1, " Creating", FNAMES.legacy_mask(til_x, til_y)) # Blur of the mask pxscal = GEO.webmercator_pixel_size(tile.lat + 0.5, tile.mask_zl) if tile.masking_mode == "sand": blur_width = int(tile.masks_width / pxscal) elif tile.masking_mode == "rocks": blur_width = tile.masks_width / (2 * pxscal) elif tile.masking_mode == "3steps": blur_width = [L / pxscal for L in tile.masks_width] if tile.masking_mode == "sand" and blur_width: # convolution with a hat function b_img_array = numpy.array(img_array) kernel = numpy.array(range(1, 2 * blur_width)) kernel[blur_width:] = range(blur_width - 1, 0, -1) kernel = kernel / blur_width**2 for i in range(0, len(b_img_array)): b_img_array[i] = numpy.convolve(b_img_array[i], kernel, 'same') b_img_array = b_img_array.transpose() for i in range(0, len(b_img_array)): b_img_array[i] = numpy.convolve(b_img_array[i], kernel, 'same') b_img_array = b_img_array.transpose() b_img_array = 2 * numpy.minimum(b_img_array, 127) b_img_array = numpy.array(b_img_array, dtype=numpy.uint8) elif tile.masking_mode == "rocks" and blur_width: # slight increase of the mask, then gaussian blur, nonlinear map and a tiny bit of smoothing again on a short scale along the shore b_img_array = (numpy.array(Image.fromarray(img_array).convert("L").\ filter(ImageFilter.GaussianBlur(blur_width / 1.7)), dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 # blur it b_img_array = numpy.array(Image.fromarray(b_img_array).convert("L").\ filter(ImageFilter.GaussianBlur(blur_width)), dtype=numpy.uint8) # nonlinear transform to make the transition quicker at the shore (gaussian is too flat) gamma = 2.5 b_img_array = (((numpy.tan((b_img_array.astype(numpy.float32) - 127.5) / 128 * atan(3)) - numpy.tan(-127.5 / 128 * atan(3)))\ *254 / (2 * numpy.tan(127.5 / 128 * atan(3)))) ** gamma / (255 ** (gamma - 1))).astype(numpy.uint8) # b_img_array=(1.4*(255-((256-b_img_array.astype(numpy.float32))/256.0)**0.2*255)).astype(numpy.uint8) # b_img_array=numpy.minimum(b_img_array,200) # still some slight smoothing at the shore b_img_array = numpy.maximum(b_img_array, numpy.array(Image.fromarray(img_array).convert("L").\ filter(ImageFilter.GaussianBlur(2 ** (tile.mask_zl - 14))), dtype=numpy.uint8)) elif tile.masking_mode == "3steps": # why trying something so complicated... transin = blur_width[0] midzone = blur_width[1] transout = blur_width[2] # print(transin,midzone,transout) shore_level = 255 b_img_array = b_mask_array = numpy.array(img_array) # First the transition at the shore # We go from shore_level to sea_level in transin meters stepsin = int(transin / 3) for i in range(stepsin): value = shore_level + transition_profile( (i + 1) / stepsin, 'parabolic') * (sea_level - shore_level) b_mask_array = (numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(1)), dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = value UI.vprint(2, value) # Next the intermediate zone at constant transparency sea_b_radius = midzone / 3 sea_b_radius_buffered = (midzone + transout) / 3 b_mask_array = (numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(sea_b_radius_buffered)), dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 b_mask_array = (numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(sea_b_radius_buffered - sea_b_radius)), dtype=numpy.uint8) == 255).astype(numpy.uint8) * 255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = sea_level # Finally the transition to the X-Plane sea # We go from sea_level to 0 in transout meters stepsout = int(transout / 3) for i in range(stepsout): value = sea_level * (1 - transition_profile( (i + 1) / stepsout, 'linear')) b_mask_array = (numpy.array(Image.fromarray(b_mask_array).convert("L").\ filter(ImageFilter.GaussianBlur(1)), dtype=numpy.uint8) > 0).astype(numpy.uint8) * 255 b_img_array[(b_img_array == 0) * (b_mask_array != 0)] = value UI.vprint(2, value) # To smoothen the thresolding introduced above we do a global short extent gaussian blur b_img_array = numpy.array(Image.fromarray(b_img_array).convert("L").\ filter(ImageFilter.GaussianBlur(2)), dtype=numpy.uint8) else: # Just a (futile) copy b_img_array = numpy.array(img_array) # Ensure land is kept to 255 on the mask to avoid unecessary ones, crop to final size, and take the # max with the possible custom extent mask img_array = numpy.maximum((img_array > 0).astype(numpy.uint8) * 255, b_img_array)[1024:4096 + 1024, 1024:4096 + 1024] img_array = numpy.maximum(img_array, custom_mask_array) if not (img_array.max() == 0 or img_array.min() == 255): masks_im = Image.fromarray( img_array) # .filter(ImageFilter.GaussianBlur(3)) masks_im.save( os.path.join(dest_dir, FNAMES.legacy_mask(til_x, til_y))) UI.vprint(2, " Done.") else: UI.vprint(1, " Ends-up being discarded.") return 1
def extract_mesh_to_obj(mesh_file,til_x_left,til_y_top,zoomlevel,provider_code): UI.red_flag=False timer=time.time() (latmax,lonmin)=GEO.gtile_to_wgs84(til_x_left,til_y_top,zoomlevel) (latmin,lonmax)=GEO.gtile_to_wgs84(til_x_left+16,til_y_top+16,zoomlevel) obj_file_name=FNAMES.obj_file(til_x_left,til_y_top,zoomlevel,provider_code) mtl_file_name=FNAMES.mtl_file(til_x_left,til_y_top,zoomlevel,provider_code) f_mesh=open(mesh_file,"r") for i in range(4): f_mesh.readline() nbr_pt_in=int(f_mesh.readline()) UI.vprint(1," Reading nodes...") pt_in=numpy.zeros(5*nbr_pt_in,'float') for i in range(nbr_pt_in): pt_in[5*i:5*i+3]=[float(x) for x in f_mesh.readline().split()[:3]] for i in range(3): f_mesh.readline() for i in range(nbr_pt_in): pt_in[5*i+3:5*i+5]=[float(x) for x in f_mesh.readline().split()[:2]] for i in range(0,2): # skip 2 lines f_mesh.readline() if UI.red_flag: UI.exit_message_and_bottom_line(); return 0 UI.vprint(1," Reading triangles...") nbr_tri_in=int(f_mesh.readline()) # read nbr of tris textured_nodes={} textured_nodes_inv={} nodes_st_coord={} len_textured_nodes=0 dico_new_tri={} len_dico_new_tri=0 for i in range(0,nbr_tri_in): (n1,n2,n3)=[int(x)-1 for x in f_mesh.readline().split()[:3]] (lon1,lat1,z1,u1,v1)=pt_in[5*n1:5*n1+5] (lon2,lat2,z2,u2,v2)=pt_in[5*n2:5*n2+5] (lon3,lat3,z3,u3,v3)=pt_in[5*n3:5*n3+5] if is_in_region((lat1+lat2+lat3)/3.0,(lon1+lon2+lon3)/3.0,latmin,latmax,lonmin,lonmax): if n1 not in textured_nodes_inv: len_textured_nodes+=1 textured_nodes_inv[n1]=len_textured_nodes textured_nodes[len_textured_nodes]=n1 nodes_st_coord[len_textured_nodes]=GEO.st_coord(lat1,lon1,til_x_left,til_y_top,zoomlevel,provider_code) n1new=textured_nodes_inv[n1] if n2 not in textured_nodes_inv: len_textured_nodes+=1 textured_nodes_inv[n2]=len_textured_nodes textured_nodes[len_textured_nodes]=n2 nodes_st_coord[len_textured_nodes]=GEO.st_coord(lat2,lon2,til_x_left,til_y_top,zoomlevel,provider_code) n2new=textured_nodes_inv[n2] if n3 not in textured_nodes_inv: len_textured_nodes+=1 textured_nodes_inv[n3]=len_textured_nodes textured_nodes[len_textured_nodes]=n3 nodes_st_coord[len_textured_nodes]=GEO.st_coord(lat3,lon3,til_x_left,til_y_top,zoomlevel,provider_code) n3new=textured_nodes_inv[n3] dico_new_tri[len_dico_new_tri]=(n1new,n2new,n3new) len_dico_new_tri+=1 nbr_vert=len_textured_nodes nbr_tri=len_dico_new_tri if UI.red_flag: UI.exit_message_and_bottom_line(); return 0 UI.vprint(1," Writing the obj file.") # first the obj file f=open(obj_file_name,"w") for i in range(1,nbr_vert+1): j=textured_nodes[i] f.write("v "+'{:.9f}'.format(pt_in[5*j]-lonmin)+" "+\ '{:.9f}'.format(pt_in[5*j+1]-latmin)+" "+\ '{:.9f}'.format(pt_in[5*j+2])+"\n") f.write("\n") for i in range(1,nbr_vert+1): j=textured_nodes[i] f.write("vn "+'{:.9f}'.format(pt_in[5*j+3])+" "+'{:.9f}'.format(pt_in[5*j+4])+" "+'{:.9f}'.format(sqrt(max(1-pt_in[5*j+3]**2-pt_in[5*j+4]**2,0)))+"\n") f.write("\n") for i in range(1,nbr_vert+1): j=textured_nodes[i] f.write("vt "+'{:.9f}'.format(nodes_st_coord[i][0])+" "+\ '{:.9f}'.format(nodes_st_coord[i][1])+"\n") f.write("\n") f.write("usemtl orthophoto\n\n") for i in range(0,nbr_tri): (one,two,three)=dico_new_tri[i] f.write("f "+str(one)+"/"+str(one)+"/"+str(one)+" "+str(two)+"/"+str(two)+"/"+str(two)+" "+str(three)+"/"+str(three)+"/"+str(three)+"\n") f_mesh.close() f.close() # then the mtl file f=open(mtl_file_name,'w') f.write("newmtl orthophoto\nmap_Kd "+FNAMES.geotiff_file_name_from_attributes(til_x_left,til_y_top,zoomlevel,provider_code)+"\n") f.close() UI.timings_and_bottom_line(timer) return
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 in ['True', 'ICAO']: UI.vprint(1, "-> Checking airport locations for upgraded zoomlevel.") 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 = {} if tile.cover_airports_with_highres == 'ICAO': airports_list = [ airport for airport in dico_airports if dico_airports[airport]['key_type'] == 'icao' ] else: airports_list = dico_airports.keys() for airport in airports_list: (xmin, ymin, xmax, ymax) = dico_airports[airport]['boundary'].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_left2, til_y_top2) = GEO.wgs84_to_orthogrid(ymin + tile.lat, xmax + tile.lon, tile.cover_zl) (ymin, xmax) = GEO.gtile_to_wgs84(til_x_left2 + 16, til_y_top2 + 16, tile.cover_zl) ymin -= tile.lat xmax -= tile.lon xmin = max(0, xmin) xmax = min(1, xmax) ymin = max(0, ymin) ymax = min(1, ymax) # 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 dico_customzl = {} dico_tmp = {} 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) 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 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) if tile.cover_airports_with_highres == 'Existing': # what we find in the texture folder of the existing tile for f in os.listdir(os.path.join(tile.build_dir, 'textures')): if f[-4:] != '.dds': continue items = f.split('_') (til_y_text, til_x_text) = [int(x) for x in items[:2]] zoomlevel = int(items[-1][-6:-4]) provider_code = '_'.join(items[2:])[:-6] for til_x in range(til_x_text * 2**(tile.mesh_zl - zoomlevel), (til_x_text + 16) * 2**(tile.mesh_zl - zoomlevel)): for til_y in range(til_y_text * 2**(tile.mesh_zl - zoomlevel), (til_y_text + 16) * 2**(tile.mesh_zl - zoomlevel)): if ((til_x, til_y) not in dico_customzl) or dico_customzl[ (til_x, til_y)][2] <= zoomlevel: dico_customzl[(til_x, til_y)] = (til_x_text, til_y_text, zoomlevel, provider_code) return dico_customzl
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.") 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 # 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_left2, til_y_top2) = GEO.wgs84_to_orthogrid(ymin + tile.lat, xmax + tile.lon, tile.cover_zl) (ymin, xmax) = GEO.gtile_to_wgs84(til_x_left2 + 16, til_y_top2 + 16, tile.cover_zl) ymin -= tile.lat xmax -= tile.lon xmin = max(0, xmin) xmax = min(1, xmax) ymin = max(0, ymin) ymax = min(1, ymax) # 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 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 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