import numpy as np

from scan import *
import cvxpy as cp
from itertools import product
import time


class Tile:
    def __init__(self, side_length=100, top_left=(0, 0), img_names=None):
        self.side_length = side_length
        self.top_left = top_left
        self.img_names = img_names

    def has_intersection(self, data):
        tl = np.array(self.top_left)
        sl = self.side_length
        pts = np.array([tl, tl + np.array([sl, 0]), tl + np.array([sl, sl]), tl + np.array([0, sl])], np.int32)
        if have_overlap(pts, 0, np.array(get_vertices(data[0]['dst_shape'], 0, 0, 0)).reshape((4, 2)), 0):
            return True
        for dat in data:
            if have_overlap(pts, 0, get_rectangle(dat), dat['angle']):
                return True
        return False

    def check_all_intersections(self, data):
        tl = np.array(self.top_left)
        sl = self.side_length
        pts = np.array([tl, tl + np.array([sl, 0]), tl + np.array([sl, sl]), tl + np.array([0, sl])], np.int32)
        img_lis = []
        if have_overlap(pts, 0, np.array(get_vertices(data[0]['dst_shape'], 0, 0, 0)).reshape((4, 2)), 0):
            img_lis.append(data[0]['dst_name'])
        for dat in data:
            if have_overlap(pts, 0, get_rectangle(dat), dat['angle']):
                img_lis.append(dat['src_name'])
        if len(img_lis) > 0:
            self.img_names = img_lis


def get_linear_ineq(rect_angle):
    rect, angle = rect_angle
    rad = angle * np.pi / 180
    slope = np.tan(rad)
    inter_1 = rect[0][1] - slope * rect[0][0]
    a1, a2, b1 = slope, - 1, - inter_1
    inter_2 = rect[3][1] - slope * rect[3][0]
    a3, a4, b2 = - slope, 1, inter_2
    inter_3 = rect[0][0] + slope * rect[0][1]
    a5, a6, b3 = - 1, - slope, - inter_3
    inter_4 = rect[1][0] + slope * rect[1][1]
    a7, a8, b4 = 1, slope, inter_4
    A1 = np.array([[a1, a2], [a3, a4]])
    B1 = np.array([b1, b2])
    A2 = np.array([[a5, a6], [a7, a8]])
    B2 = np.array([b3, b4])
    # print(A1, B1)
    # print(A2, B2)
    return A1, B1, A2, B2


def have_overlap(rect_1, angle_1, rect_2, angle_2):
    p0 = rect_1[0]
    shifted_1 = copy.copy(rect_1)
    shifted_2 = copy.copy(rect_2)
    for i in range(4):
        shifted_1[i] = rect_1[i] - np.array(p0)
        shifted_2[i] = rect_2[i] - np.array(p0)
    center_1 = get_center(shifted_1)
    center_2 = get_center(shifted_2)
    r_1 = get_gc_radius(shifted_1)
    r_2 = get_gc_radius(shifted_2)
    distance = np.sqrt((center_1[0] - center_2[0])**2 + (center_1[1] - center_2[1])**2)
    if distance >= r_1 + r_2:
        return False
    else:
        A1, B1, A2, B2 = get_linear_ineq(order_rectangle(shifted_1, angle_1))
        A3, B3, A4, B4 = get_linear_ineq(order_rectangle(shifted_2, angle_2))
        x = cp.Variable(2)
        prob = cp.Problem(cp.Minimize(2), [A1 @ x <= B1, A2 @ x <= B2, A3 @ x <= B3, A4 @ x <= B4])
        try:
            prob.solve()
        except cp.error.SolverError:
            print('Solver error')
            return True
        solution = x.value
        return solution is not None


def order_rectangle(rect, angle):
    quadrant = int(angle // 90)
    if quadrant < 0:
        quadrant += 1
    new_rect = np.zeros_like(rect)
    for i in range(4):
        new_rect[i] = rect[(i + quadrant) % 4]
    return new_rect, - (angle - quadrant * 90)


def get_rectangle(dat):
    return get_vertices(np.array(dat['src_shape']) * dat['scale'], dat['angle'], dat['x'], dat['y']).reshape((4, 2))


def get_gc_radius(rect):
    p1, p2, p3, p4 = rect
    center = get_center(rect)
    r_x = p1[0] - center[0]
    r_y = p1[1] - center[1]
    return np.sqrt(r_x**2 + r_y**2)


def get_center(rect):
    p1, p2, p3, p4 = rect
    c_x = (p1[0] + p3[0])/2
    c_y = (p1[1] + p3[1])/2
    return c_x, c_y


def get_warp_scale(data, name):
    for dat in data:
        if dat['src_name'] == name:
            return dat['scale']
        elif dat['dst_name'] == name:
            return 1


def get_angle(data, name):
    for dat in data:
        if dat['src_name'] == name:
            return dat['angle']
        elif dat['dst_name'] == name:
            return 0


def get_translation_vec(data, name):
    for dat in data:
        if dat['src_name'] == name:
            return dat['x'], dat['y']
        elif dat['dst_name'] == name:
            return 0, 0


def get_data_from_names(data, names):
    ret_data = []
    for name in names:
        for dat in data:
            if dat['src_name'] == name:
                ret_data.append(dat)
    return ret_data


def scale_data(data, factor, img_path):
    new_data = copy.deepcopy(data)
    for dat in new_data:
        dat['src_shape'] = get_img_shape(img_path + dat['src_name'])
        dat['dst_shape'] = get_img_shape(img_path + dat['dst_name'])
        dat['x'] = dat['x'] * factor
        dat['y'] = dat['y'] * factor
    return new_data


def smart_slice(out_img, in_img, x, y):
    xmin = max(0, x)
    xmax = min(x + out_img.shape[0], in_img.shape[1])
    ymin = max(0, y)
    ymax = min(y + out_img.shape[1], in_img.shape[0])
    tile_xmin = max(0, -x)
    tile_xmax = min(in_img.shape[1] - x, out_img.shape[1])
    tile_ymin = max(0, -y)
    tile_ymax = min(in_img.shape[0] - y, out_img.shape[0])
    out_img[tile_ymin: tile_ymax, tile_xmin: tile_xmax] = in_img[ymin: ymax, xmin: xmax]
    return out_img


def get_2nd_part():
    part_2_data = [{'src_name': '52_3.jpg', 'src_shape': [4748, 3369], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 0.61, 'scale': 1.0024, 'x': -45, 'y': 779},
                   {'src_name': '52_2.jpg', 'src_shape': [4748, 3369], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 121.05, 'scale': 1.0024, 'x': 4230, 'y': 4540},
                   {'src_name': '52_1.jpg', 'src_shape': [4748, 3369], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -28.7, 'scale': 1.0012, 'x': 3650, 'y': -653},
                   {'src_name': '53.jpg', 'src_shape': [4748, 3413], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 60.85, 'scale': 1.0, 'x': 3819, 'y': 519},
                   {'src_name': '54.jpg', 'src_shape': [4724, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 60.75, 'scale': 1.0020, 'x': 5584, 'y': -2669},
                   {'src_name': '55.jpg', 'src_shape': [4736, 3405], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 61.15, 'scale': 1.0, 'x': 7369, 'y': -5877},
                   {'src_name': '57_3.jpg', 'src_shape': [4745, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -119.13, 'scale': 1.0, 'x': 14440, 'y': -11588},
                   {'src_name': '56.jpg', 'src_shape': [4752, 3397], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 41.4, 'scale': 1.0, 'x': 9718, 'y': -10073},
                   {'src_name': '57_2.jpg', 'src_shape': [4745, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 25.55, 'scale': 1.0, 'x': 11525, 'y': -12236},
                   {'src_name': '58.jpg', 'src_shape': [4744, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 10.4, 'scale': 1.0, 'x': 13892, 'y': -13531},
                   {'src_name': '59_2.jpg', 'src_shape': [4733, 3368], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -154.35, 'scale': 1.0, 'x': 16968, 'y': -12757},
                   {'src_name': '59_1.jpg', 'src_shape': [4733, 3368], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 10.4, 'scale': 1.003, 'x': 13637, 'y': -15000},
                   {'src_name': '60.jpg', 'src_shape': [4733, 3397], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 10.6, 'scale': 1.0, 'x': 17545, 'y': -14197},
                   {'src_name': '62_2.jpg', 'src_shape': [4728, 3377], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -169.8, 'scale': 1.003, 'x': 22479, 'y': -13209},
                   {'src_name': '57_1.jpg', 'src_shape': [4745, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 10.5, 'scale': 1.0045, 'x': 21161, 'y': -14884},
                   {'src_name': '61.jpg', 'src_shape': [4752, 3412], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 26.4, 'scale': 1.0, 'x': 21182, 'y': -14751},
                   {'src_name': '62_1.jpg', 'src_shape': [4728, 3377], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 26.85, 'scale': 1.005, 'x': 20537, 'y': -16075},
                   {'src_name': '64_1.jpg', 'src_shape': [4724, 3373], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -143.15, 'scale': 1.005, 'x': 27877, 'y': -14670},
                   {'src_name': '63.jpg', 'src_shape': [4744, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 47.3, 'scale': 1.0, 'x': 24525, 'y': -16234},
                   {'src_name': '64_2.jpg', 'src_shape': [4724, 3373], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 72.8, 'scale': 1.0, 'x': 26237, 'y': -16670},
                   {'src_name': '65.jpg', 'src_shape': [4740, 3409], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 99.0, 'scale': 1.0, 'x': 27415, 'y': -18634},
                   {'src_name': '67_1.jpg', 'src_shape': [4728, 3377], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 81.2, 'scale': 1.005, 'x': 26670, 'y': -22228},
                   {'src_name': '66.jpg', 'src_shape': [4728, 3396], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 63.85, 'scale': 1.002, 'x': 26830, 'y': -24255},
                   {'src_name': '67_2.jpg', 'src_shape': [4728, 3377], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': -129.7, 'scale': 1.002, 'x': 33868, 'y': -28984},
                   {'src_name': '68.jpg', 'src_shape': [4744, 3389], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 37.25, 'scale': 1.0, 'x': 29216, 'y': -28822},
                   {'src_name': '73_1.jpg', 'src_shape': [4727, 3373], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 44.8, 'scale': 1.008, 'x': 31870, 'y': -30751},
                   {'src_name': '69.jpg', 'src_shape': [4717, 3401], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 54.1, 'scale': 1.0, 'x': 32224, 'y': -30925},
                   {'src_name': '70.jpg', 'src_shape': [4732, 3397], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 53.8, 'scale': 1.0, 'x': 34367, 'y': -33860},
                   {'src_name': '71.jpg', 'src_shape': [4756, 3365], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 53.95, 'scale': 1.003, 'x': 36849, 'y': -32020},
                   {'src_name': '72.jpg', 'src_shape': [2396, 3373], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 53.7, 'scale': 1.0, 'x': 39235, 'y': -35341},
                   {'src_name': '73_2.jpg', 'src_shape': [4727, 3373], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 53.4, 'scale': 1.0, 'x': 35643, 'y': -35600},
                   {'src_name': '74.jpg', 'src_shape': [4764, 3363], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 96.25, 'scale': 1.005, 'x': 36905, 'y': -36551},
                   {'src_name': '75.jpg', 'src_shape': [4744, 3369], 'dst_name': '51.jpg', 'dst_shape': [4740, 3401],
                    'angle': 96.35, 'scale': 1.0, 'x': 36510, 'y': -40313}
                   ]
    return part_2_data


def get_connection_1_2():
    return {'src_name': '51.jpg', 'src_shape': [4740, 3401], 'dst_name': '50.jpg', 'dst_shape': [4085, 6174],
            'angle': -0.125, 'scale': 0.9975, 'x': 3490, 'y': 1377}


def transform_2nd_part():
    part_2_data = get_2nd_part()
    conn_to_part_2 = get_connection_1_2()
    conn_data = [invert_coord_frame(conn_to_part_2)] + part_2_data
    conn_data_ext = [invert_coord_frame(all_comp_scaled[34])] + conn_data
    trafo_data = transform_data_relative_to_first(conn_data_ext[:2])[1]
    new_data = [trafo_data]
    trafo_data = invert_coord_frame(trafo_data)
    for dat in part_2_data:
        new_data.append(transform_data_relative_to_first([trafo_data, invert_coord_frame(dat)])[1])
    return new_data


def prepare_tiles(data, side_length, roi, power=3):
    scale = 2 ** power
    tiles = generate_tiles(scale * side_length, roi)
    while scale > 1:
        tiles = list(filter(lambda x: x.has_intersection(data), tiles))
        scale = scale // 2
        smaller_tiles = []
        for tile in tiles:
            loc_roi = (tile.top_left[0], tile.top_left[1], tile.side_length, tile.side_length)
            new_tiles = generate_tiles(scale * side_length, loc_roi)
            smaller_tiles += new_tiles
        tiles = smaller_tiles
    for tile in tiles:
        tile.check_all_intersections(data)
    tiles = list(filter(lambda x: x.img_names is not None, tiles))
    return tiles


def generate_tiles(side_length, roi):
    x_range = range(roi[0], roi[0] + roi[2], side_length)
    y_range = range(roi[1], roi[1] + roi[3], side_length)
    corners = product(x_range, y_range)
    tiles = [Tile(side_length, top_left) for top_left in corners]
    return tiles


def register_tiles(data, side_length, incl_first=True):
    start = time.time()
    roi = get_roi(data, incl_first)
    print(roi)
    tiles = prepare_tiles(data, side_length, roi, power=5)
    elapsed = time.time() - start
    print('time used for checking intersections: ' + str(int(elapsed)) + ' s')
    tile_dict = {}
    for tile in tiles:
        if tuple(tile.img_names) in tile_dict.keys():
            tile_dict[tuple(tile.img_names)] += [tile.top_left]
        else:
            tile_dict[tuple(tile.img_names)] = [tile.top_left]
    return tile_dict


def draw_tiles(data, tile_dict, side_length=200, incl_first=True):
    start = time.time()
    roi = get_roi(data, incl_first)
    print(roi)
    for names, tile_corners in tile_dict.items():
        blender = cv.detail_MultiBandBlender()
        # blend_width = 10
        # num_bands = np.log(blend_width) / np.log(2.) - 1.
        blender.setNumBands(2)
        # blender = cv.detail_FeatherBlender()
        if (len(names) == 1) and ('9.jpg' in names):
            local_roi = (0, 0, data[0]['dst_shape'][0], data[0]['dst_shape'][1])
        else:
            local_incl_first = '9.jpg' in names
            local_roi = get_roi(get_data_from_names(data, names), local_incl_first)
        print(local_roi, names)
        blender.prepare(local_roi)
        for name in names:
            warper = cv.PyRotationWarper('affine', get_warp_scale(data, name))
            img = cv.imread(f'imgs/danube_50_pct/{name}').astype(np.int16)
            mask_path_10pct = pathlib.Path(f'imgs/danube_10_pct/masks/mask_{name}'.replace('.jpg', '.png'))
            mask_path_50pct = pathlib.Path(f'imgs/danube_50_pct/masks/mask_{name}'.replace('.jpg', '.png'))
            if mask_path_10pct.exists():
                mask = cv.imread(mask_path_10pct.as_posix(), flags=cv.IMREAD_GRAYSCALE)
                mask = cv.blur(mask, (7, 7))
                mask = cv.resize(src=mask, dsize=(img.shape[1], img.shape[0]), fx=0, fy=0,
                                 interpolation=cv.INTER_CUBIC)
                ret, mask = cv.threshold(mask, 127, 255, cv.THRESH_BINARY)
            elif mask_path_50pct.exists():
                mask = cv.imread(mask_path_50pct.as_posix(), flags=cv.IMREAD_GRAYSCALE)
                mask = cv.blur(mask, (25, 25))
                ret, mask = cv.threshold(mask, 127, 255, cv.THRESH_BINARY)
            else:
                print('no mask loaded!')
                return
            corner, img = warper.warp(img, get_3x3_id(), compose_R_mat(get_angle(data, name), 1, 0, 0),
                                      # cv.INTER_LINEAR, cv.BORDER_REFLECT)
                                      cv.INTER_LINEAR, cv.BORDER_CONSTANT)
            corner, mask = warper.warp(mask, get_3x3_id(), compose_R_mat(get_angle(data, name), 1, 0, 0),
                                       cv.INTER_LINEAR, cv.BORDER_CONSTANT)
            corner = (corner[0] + round(get_translation_vec(data, name)[0]),
                      corner[1] + round(get_translation_vec(data, name)[1]))
            blender.feed(cv.UMat(img), cv.UMat(mask), corner)
        result, result_mask = blender.blend(None, None)
        for tl in tile_corners:
            tile_img = np.zeros((side_length, side_length, 3), np.int16)
            slice_x = tl[0] - local_roi[0]
            slice_y = tl[1] - local_roi[1]
            img_slice = np.zeros((side_length, side_length, 3), np.int16)
            img_slice = smart_slice(img_slice, result, slice_x, slice_y)
            mask_slice = 255 * np.ones((side_length, side_length), np.uint8)
            mask_slice = smart_slice(mask_slice, result_mask, slice_x, slice_y)
            mask_slice_inv = cv.bitwise_not(mask_slice)
            tile_img = cv.bitwise_and(tile_img, tile_img, mask=mask_slice_inv)
            img_slice = cv.bitwise_and(img_slice, img_slice, mask=mask_slice)
            tile_img = cv.add(tile_img, img_slice)
            if np.sum(tile_img) > 0:
                cv.imwrite(
                    f'imgs_out/tiles/tile_{(tl[0] - roi[0])//side_length}_{(tl[1] - roi[1])//side_length}.tif',
                    tile_img)
    total_time = time.time() - start
    print('total drawing time needed: ' + str(int(total_time)) + ' s')


def draw_images(data, draw_first=True, scaling=0.5):
    dst_sz = get_roi(data, draw_first)
    print(dst_sz)
    blender = cv.detail_MultiBandBlender()
    blender.setNumBands(2)
    blender.prepare(dst_sz)
    if draw_first:
        img = cv.imread('imgs/danube_50_pct/9.jpg').astype(np.int16)
        mask = cv.imread('imgs/danube_10_pct/masks/mask_9.png', flags=cv.IMREAD_GRAYSCALE)
        mask = cv.blur(mask, (7, 7))
        mask = cv.resize(src=mask, dsize=(img.shape[1], img.shape[0]), fx=0, fy=0, interpolation=cv.INTER_CUBIC)
        ret, mask = cv.threshold(mask, 127, 255, cv.THRESH_BINARY)
        blender.feed(cv.UMat(img), cv.UMat(mask), (0, 0))
    for dat in data:
        warper = cv.PyRotationWarper('affine', dat['scale'])
        img = cv.imread(f'imgs/danube_50_pct/{dat["src_name"]}').astype(np.int16)
        corner, img = warper.warp(img, get_3x3_id(), compose_R_mat(dat['angle'], 1, 0, 0),
                                  cv.INTER_LINEAR, cv.BORDER_REFLECT)
                                  # cv.INTER_NEAREST, cv.BORDER_CONSTANT)
        mask_path_10pct = pathlib.Path(f'imgs/danube_10_pct/masks/mask_{dat["src_name"]}'.replace('.jpg', '.png'))
        mask_path_50pct = pathlib.Path(f'imgs/danube_50_pct/masks/mask_{dat["src_name"]}'.replace('.jpg', '.png'))
        if mask_path_10pct.exists():
            mask = cv.imread(mask_path_10pct.as_posix(), flags=cv.IMREAD_GRAYSCALE)
            mask = cv.blur(mask, (7, 7))
            mask = cv.resize(src=mask, dsize=(dat['src_shape'][0], dat['src_shape'][1]), fx=0, fy=0,
                             interpolation=cv.INTER_CUBIC)
            ret, mask = cv.threshold(mask, 127, 255, cv.THRESH_BINARY)
        else:
            mask = cv.imread(mask_path_50pct.as_posix(), flags=cv.IMREAD_GRAYSCALE)
        # mask = cv.blur(mask, (30, 30))
        # ret, mask = cv.threshold(mask, 127, 255, cv.THRESH_BINARY)
        corner, mask = warper.warp(mask, get_3x3_id(), compose_R_mat(dat['angle'], 1, 0, 0),
                                   cv.INTER_NEAREST, cv.BORDER_CONSTANT)
        corner = (corner[0] + round(dat['x']), corner[1] + round(dat['y']))
        print(dat['src_name'], corner, img.shape)
        blender.feed(cv.UMat(img), cv.UMat(mask), corner)
    result, result_mask = blender.blend(None, None)
    if scaling != 1:
        result = cv.resize(result, None, fx=scaling, fy=scaling, interpolation=cv.INTER_AREA)
        result_mask = cv.resize(result_mask, None, fx=scaling, fy=scaling, interpolation=cv.INTER_AREA)
    cv.imwrite('tdi_2.png', result)
    cv.imwrite('tdi_2_mask.png', result_mask)


if __name__ == '__main__':
    # with open('stitch_data.json', 'r') as fp:
    #     components = json.load(fp)
    # components = do_corrections(components)
    # all_comp = collect_all_components(components)
    # all_comp_scaled = scale_data(all_comp, 5, img_path='imgs/danube_50_pct/')
    # all_comp_scaled = scale_data(all_comp, 10, img_path='imgs/danube_100_pct/')
    # with open('50pct_stitch_data.json', 'w') as fp:
    #     json.dump(all_comp_scaled, fp)
    # with open('100pct_stitch_data.json', 'w') as fp:
    #     json.dump(all_comp_scaled, fp)
    with open('50pct_stitch_data.json', 'r') as fp:
        all_comp_scaled = json.load(fp)
    # with open('100pct_stitch_data.json', 'r') as fp:
    #     all_comp_scaled = json.load(fp)
    # rect5 = get_rectangle(all_comp[21])
    # rect6 = get_rectangle(all_comp[22])
    # res = have_overlap(rect5, all_comp[21]['angle'], rect6, all_comp[22]['angle'])
    # print(res)
    # if res is not None:
    #     roi = get_roi(all_comp[21:23], incl_first=False)
    #     circ_x = round(res[0] - roi[0])
    #     circ_y = round(res[1] - roi[1])
    #     print(circ_x)
    #     print(circ_y)
    #     img = cv.circle(img, (circ_x, circ_y), radius=5, color=0, thickness=-1)
    # roi = get_roi(all_comp[0:4], incl_first=True)
    # tile = Tile(200, (600, 40), roi)
    # print(tile.is_out_of_roi())
    # tile.check_intersections(all_comp[0:4])
    # print(tile.img_names)
    # img = draw_rectangles_from_data(all_comp[0:4], draw_first=True)
    # img = cv.rectangle(img, (tile.top_left[0] - roi[0], tile.top_left[1] - roi[1]),
    #                    (tile.top_left[0] + tile.side_length - roi[0], tile.top_left[1] + tile.side_length - roi[1]),
    #                    0, thickness=10, lineType=cv.LINE_8)
    # cv.imwrite('test.png', img)
    # draw_tiles(all_comp[14:19] + all_comp[-6:], incl_first=False)

    # # create tile data:
    # tile_dict = register_tiles(all_comp_scaled, side_length=500, incl_first=True)
    # tile_dict_no_tuple = {}
    # for key, value in tile_dict.items():
    #     tile_dict_no_tuple[str(key)] = value
    # with open('tile_data.json', 'w') as fp:
    #     json.dump(tile_dict_no_tuple, fp)

    # load tile data:
    # with open('tile_data.json', 'r') as fp:
    #     tile_dict_no_tup = json.load(fp)
    # tile_dict = {}
    # for key, value in tile_dict_no_tup.items():
    #     tile_dict[eval(key)] = value
    # print(get_gc_radius([[-1, -1], [3, -1], [3, 1], [-1, 1]]))
    # print(get_center([[-1, -1], [3, -1], [3, 1], [-1, 1]]))
    # print(get_gc_radius([[-1, 0], [3, 0], [3, 2], [-1, 2]]))
    # print(get_center([[-1, 0], [3, 0], [3, 2], [-1, 2]]))
    # dat_15 = {"src_name": "15.jpg", "src_shape": [11759, 7230], "dst_name": "9.jpg", "dst_shape": [8448, 6271],
    # "angle": 30.68075628506069, "scale": 1.0009182704184914, "x": 42887.81547783238, "y": -3841.5277625327826}
    # rect_15 = get_rectangle(dat_15)
    # rect_tile = np.array([[44000, 894], [48000, 894], [48000, 4894], [44000, 4894]])
    # print(rect_15, rect_tile)
    # tile = Tile(side_length=4000, top_left=(44000, 894))
    # center_1 = get_center(rect_15)
    # center_2 = get_center(rect_tile)
    # print(center_1, center_2)
    # r_1 = get_gc_radius(rect_15)
    # r_2 = get_gc_radius(rect_tile)
    # distance = np.sqrt((center_1[0] - center_2[0]) ** 2 + (center_1[1] - center_2[1]) ** 2)
    # print(r_1, r_2, np.sqrt(8))
    # print(distance, r_1 + r_2)
    # print(tile.has_intersection([dat_15]))

    # tile_dict = register_tiles(all_comp_scaled, side_length=3000, incl_first=True)

    complete_data = all_comp_scaled + transform_2nd_part()
    # with open('complete_data.json', 'w') as fp:
    #     json.dump(complete_data, fp)
    for i, dat in enumerate(complete_data):
        print(i, dat)
    # draw_images([complete_data[34], complete_data[41]], False, scaling=0.5)

    # tiles_dict = register_tiles(complete_data, side_length=3000, incl_first=True)
    # tiles_dict_old = register_tiles(all_comp_scaled, side_length=3000, incl_first=True)
    # old_keys = tiles_dict_old.keys()
    # new_keys = tiles_dict.keys()
    # diff_keys = list(set(new_keys) - set(old_keys))
    # tiles_dict_subset = {k: tiles_dict[k] for k in diff_keys}
    # # for k, val in tiles_dict_subset.items():
    # #     print(k, val)
    #
    # draw_tiles(complete_data, tiles_dict_subset, side_length=3000, incl_first=True)
    # test_img = draw_rectangles_from_data([complete_data[64], complete_data[65]], draw_first=False)
    # cv.imwrite('test_img.png', test_img)
    # rect_1 = get_rectangle(complete_data[64])
    # rect_2 = get_rectangle(complete_data[65])
    # rect_3 = get_rectangle(complete_data[66])
    # print(rect_1)
    # print(rect_2)
    # print(have_overlap(rect_1, complete_data[64]['angle'], rect_2, complete_data[65]['angle']))

    # img = cv.imread('imgs/danube_50_pct/9.jpg').astype(np.int16)
    # mask = cv.imread('imgs/danube_10_pct/masks/mask_9.png', flags=cv.IMREAD_GRAYSCALE)
    # mask = resize_mask(mask, img)
    # print(mask.shape)
    # print(img.shape)
    #
    # debug in the case angle > pi/4:
    # rect1 = get_rectangle(all_comp[5])
    # rect2 = get_rectangle(all_comp[6])
    # print(have_overlap(rect1, all_comp[5]['angle'], rect2, all_comp[6]['angle']))
