Example #1
0
def download_textures(tile,download_queue,convert_queue):
    UI.vprint(1,"-> Opening download queue.")
    done=0
    while True:
        texture_attributes=download_queue.get()
        if isinstance(texture_attributes,str) and texture_attributes=='quit':
            UI.progress_bar(2,100)
            break
        if IMG.build_jpeg_ortho(tile,*texture_attributes):
            done+=1
            UI.progress_bar(2,int(100*done/(done+download_queue.qsize()))) 
            convert_queue.put((tile,*texture_attributes))
        if UI.red_flag: UI.vprint(1,"Download process interrupted."); return 0
    if done: UI.vprint(1," *Download of textures completed.") 
    return 1
Example #2
0
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
Example #3
0
    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
Example #4
0
              "directory, check your install. Exiting.")
        sys.exit()
    for directory in (FNAMES.Preview_dir, FNAMES.Provider_dir,
                      FNAMES.Extent_dir, FNAMES.Filter_dir, FNAMES.OSM_dir,
                      FNAMES.Mask_dir, FNAMES.Imagery_dir,
                      FNAMES.Elevation_dir, FNAMES.Geotiff_dir,
                      FNAMES.Patch_dir, FNAMES.Tile_dir, FNAMES.Tmp_dir):
        if not os.path.isdir(directory):
            try:
                os.makedirs(directory)
                print("Creating missing directory", directory)
            except:
                print("Could not create required directory", directory,
                      ". Exit.")
                sys.exit()
    IMG.initialize_extents_dict()
    IMG.initialize_color_filters_dict()
    IMG.initialize_providers_dict()
    IMG.initialize_combined_providers_dict()
    if len(sys.argv) == 1:  # switch to the graphical interface
        Ortho4XP = GUI.Ortho4XP_GUI()

        Ortho4XP.mainloop()
        print("Bon vol!")
    else:  # sequel is only concerned with command line
        if len(sys.argv) < 3:
            print(cmd_line)
            sys.exit()
        try:
            lat = int(sys.argv[1])
            lon = int(sys.argv[2])
def build_tile(tile):
    if UI.is_working: return 0
    UI.is_working = 1
    UI.red_flag = False
    UI.logprint("Step 3 for tile lat=", tile.lat, ", lon=", tile.lon,
                ": starting.")
    UI.vprint(
        0, "\nStep 3 : Building DSF/Imagery for tile " +
        FNAMES.short_latlon(tile.lat, tile.lon) + " : \n--------\n")

    if not os.path.isfile(FNAMES.mesh_file(tile.build_dir, tile.lat,
                                           tile.lon)):
        UI.lvprint(
            0, "ERROR: A mesh file must first be constructed for the tile!")
        UI.exit_message_and_bottom_line('')
        return 0

    timer = time.time()

    tile.write_to_config()

    if not IMG.initialize_local_combined_providers_dict(tile):
        UI.exit_message_and_bottom_line('')
        return 0

    try:
        if not os.path.exists(
                os.path.join(tile.build_dir, 'Earth nav data',
                             FNAMES.round_latlon(tile.lat, tile.lon))):
            os.makedirs(
                os.path.join(tile.build_dir, 'Earth nav data',
                             FNAMES.round_latlon(tile.lat, tile.lon)))
        if not os.path.isdir(os.path.join(tile.build_dir, 'textures')):
            os.makedirs(os.path.join(tile.build_dir, 'textures'))
        if UI.cleaning_level > 1 and not tile.grouped:
            for f in os.listdir(os.path.join(tile.build_dir, 'textures')):
                if f[-4:] != '.png': continue
                try:
                    os.remove(os.path.join(tile.build_dir, 'textures', f))
                except:
                    pass
        if not tile.grouped:
            try:
                shutil.rmtree(os.path.join(tile.build_dir, 'terrain'))
            except:
                pass
        if not os.path.isdir(os.path.join(tile.build_dir, 'terrain')):
            os.makedirs(os.path.join(tile.build_dir, 'terrain'))
    except Exception as e:
        UI.lvprint(0, "ERROR: Cannot create tile subdirectories.")
        UI.vprint(3, e)
        UI.exit_message_and_bottom_line('')
        return 0

    download_queue = queue.Queue()
    convert_queue = queue.Queue()
    build_dsf_thread = threading.Thread(target=DSF.build_dsf,
                                        args=[tile, download_queue])
    download_thread = threading.Thread(
        target=download_textures, args=[tile, download_queue, convert_queue])
    build_dsf_thread.start()
    if not skip_downloads:
        download_thread.start()
        if not skip_converts and not O4_ESP_Globals.build_for_ESP:
            UI.vprint(1, "-> Opening convert queue and", max_convert_slots,
                      "conversion workers.")
            dico_conv_progress = {'done': 0, 'bar': 3}
            convert_workers = parallel_launch(IMG.convert_texture,
                                              convert_queue,
                                              max_convert_slots,
                                              progress=dico_conv_progress)
    build_dsf_thread.join()
    if not skip_downloads:
        download_queue.put('quit')
        download_thread.join()
        if not skip_converts and not O4_ESP_Globals.build_for_ESP:
            for _ in range(max_convert_slots):
                convert_queue.put('quit')
            parallel_join(convert_workers)
            if UI.red_flag:
                UI.vprint(1, "DDS conversion process interrupted.")
            elif dico_conv_progress['done'] >= 1:
                UI.vprint(1, " *DDS conversion of textures completed.")
    UI.vprint(1, " *Activating DSF file.")
    dsf_file_name = os.path.join(
        tile.build_dir, 'Earth nav data',
        FNAMES.long_latlon(tile.lat, tile.lon) + '.dsf')
    try:
        os.rename(dsf_file_name + '.tmp', dsf_file_name)
    except:
        UI.vprint(0, "ERROR : could not rename DSF file, tile is not actived.")
    if UI.red_flag:
        UI.exit_message_and_bottom_line()
        return 0
    if UI.cleaning_level > 1:
        try:
            os.remove(FNAMES.alt_file(tile))
        except:
            pass
        try:
            os.remove(FNAMES.input_node_file(tile))
        except:
            pass
        try:
            os.remove(FNAMES.input_poly_file(tile))
        except:
            pass
    if UI.cleaning_level > 2:
        try:
            os.remove(FNAMES.mesh_file(tile.build_dir, tile.lat, tile.lon))
        except:
            pass
        try:
            os.remove(FNAMES.apt_file(tile))
        except:
            pass
    if UI.cleaning_level > 1 and not tile.grouped:
        remove_unwanted_textures(tile)
    if O4_ESP_Globals.build_for_ESP:
        O4_ESP_Utils.run_ESP_resample(O4_ESP_Globals.ESP_build_dir)

    UI.timings_and_bottom_line(timer)
    UI.logprint("Step 3 for tile lat=", tile.lat, ", lon=", tile.lon,
                ": normal exit.")
    return 1
Example #6
0
def build_tile(tile):
    UI.red_flag = False
    UI.logprint("Step 3 for tile lat=", tile.lat, ", lon=", tile.lon,
                ": starting.")
    UI.vprint(
        0, "\nStep 3 : Building DSF/Imagery for tile " +
        FNAMES.short_latlon(tile.lat, tile.lon) + " : \n--------\n")

    if not os.path.isfile(FNAMES.mesh_file(tile.build_dir, tile.lat,
                                           tile.lon)):
        UI.lvprint(
            0, "ERROR: A mesh file must first be constructed for the tile!")
        UI.exit_message_and_bottom_line('')
        return 0

    timer = time.time()

    tile.write_to_config()
    #tile.ensure_elevation_data()

    IMG.initialize_local_combined_providers_dict(tile)

    try:
        if not os.path.exists(
                os.path.join(tile.build_dir, 'Earth nav data',
                             FNAMES.round_latlon(tile.lat, tile.lon))):
            os.makedirs(
                os.path.join(tile.build_dir, 'Earth nav data',
                             FNAMES.round_latlon(tile.lat, tile.lon)))
        if not os.path.isdir(os.path.join(tile.build_dir, 'textures')):
            os.makedirs(os.path.join(tile.build_dir, 'textures'))
        try:
            shutil.rmtree(os.path.join(tile.build_dir, 'terrain'))
        except:
            pass
        if not os.path.isdir(os.path.join(tile.build_dir, 'terrain')):
            os.makedirs(os.path.join(tile.build_dir, 'terrain'))
    except Exception as e:
        UI.lvprint(0, "ERROR: Cannot create tile subdirectories.")
        UI.vprint(3, e)
        UI.exit_message_and_bottom_line('')
        return 0

    download_queue = queue.Queue()
    convert_queue = queue.Queue()
    build_dsf_thread = threading.Thread(target=DSF.build_dsf,
                                        args=[tile, download_queue])
    download_thread = threading.Thread(
        target=download_textures, args=[tile, download_queue, convert_queue])
    build_dsf_thread.start()
    if not skip_downloads:
        download_thread.start()
        if not skip_converts:
            UI.vprint(1, "-> Opening convert queue and", max_convert_slots,
                      "conversion workers.")
            dico_conv_progress = {'done': 0, 'bar': 3}
            convert_workers = parallel_launch(IMG.convert_texture,
                                              convert_queue,
                                              max_convert_slots,
                                              progress=dico_conv_progress)
    build_dsf_thread.join()
    if not skip_downloads:
        download_queue.put('quit')
        download_thread.join()
        if not skip_converts:
            for _ in range(max_convert_slots):
                convert_queue.put('quit')
            parallel_join(convert_workers)
            if UI.red_flag:
                UI.vprint(1, "DDS conversion process interrupted.")
            elif dico_conv_progress['done'] >= 1:
                UI.vprint(1, " *DDS conversion of textures completed.")
    if UI.red_flag:
        UI.exit_message_and_bottom_line()
        return 0
    UI.timings_and_bottom_line(timer)
    UI.logprint("Step 3 for tile lat=", tile.lat, ", lon=", tile.lon,
                ": normal exit.")
    return 1