#!D:/IDE/anaconda3/envs python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName：SlidePointUtils.py\n
 @DateTime: 2025/6/30 13:10\n
 @Author  ：xsh
"""
from PyQt5 import Qt
import numpy as np
from decimal import Decimal
class SlidePointUtils:
    """坐标变换"""
    @staticmethod
    def detect_point_transforms(target_x: int, target_y: int, image_w: int, image_h: int, width: float, height: float, axis_offset_w: float, axis_offset_h: float, img_offset_w: float, img_offset_h: float) -> (float, float):
        tr_x = image_w - target_x
        tr_y = target_y
        _image_w: Decimal = Decimal(f'{image_w}') / 2
        _image_h: Decimal = Decimal(f'{image_h}') / 2
        _tr_x: Decimal = Decimal(f'{float(tr_x)}')
        _tr_y: Decimal = Decimal(f'{float(tr_y)}')
        scale_x: Decimal = Decimal(f'{float(width)}') / Decimal(f'{float(image_w)}')
        scale_y: Decimal = Decimal(f'{float(height)}') / Decimal(f'{float(image_h)}')
        offset_x: Decimal = Decimal(f'{axis_offset_w}') / Decimal(f'{img_offset_w}')
        offset_y: Decimal = Decimal(f'{axis_offset_h}') / Decimal(f'{img_offset_h}')
        point_x: Decimal = Decimal((_tr_x - _image_w) * scale_x + offset_x)
        point_y: Decimal = Decimal((_tr_y - _image_h) * scale_y + offset_y)
        return float(point_x), float(point_y)

    @staticmethod
    def detect_point_transforms_100X(target_x: int, target_y: int, image_w: int, image_h: int, axis_offset_w: float, axis_offset_h: float, img_offset_w: float, img_offset_h: float) -> (float, float):
        point_w: Decimal =  Decimal(f'{0}')
        point_h: Decimal =  Decimal(f'{0}')
        try:
            tr_w = image_w - target_x
            tr_h = target_y
            _tr_w: Decimal = Decimal(f'{tr_w}')
            _tr_h: Decimal = Decimal(f'{tr_h}')
            _image_w: Decimal = Decimal(f'{image_w}') / 2
            _image_h: Decimal = Decimal(f'{image_h}') / 2
            scale_w: Decimal = Decimal(f'{axis_offset_w}') / Decimal(f'{img_offset_w}')
            scale_h: Decimal = Decimal(f'{axis_offset_h}') / Decimal(f'{img_offset_h}')
            point_w: Decimal = (_tr_w - _image_w) * scale_w
            point_h: Decimal = (_tr_h - _image_h) * scale_h
        except Exception as e:
            pass

        return float(point_w), float(point_h)

    @staticmethod
    def SlideFocusArray(left: int, top: int, width: int, height: int, max_row: int, max_col: int, focus_rows: int, focus_cols: int, re_row_col: bool = False) -> list[list[int]]:
        """
        :param max_col: 最大格子数    薄片列数
        :param max_row: 最小格子数    薄片行数
        :param left: 起始位置格子列号
        :param top:  起始位置格子行号
        :param width: 格子宽度 平扫的列数    扫描区域
        :param height: 格子高度 平扫的行数   扫描区域
        :param focus_rows: 定焦点行数    # 打点
        :param focus_cols: 定焦点列数    # 打点
        :param re_row_col: 返回格式是否为先行后列  # 如果是True，则为 row/col/(X,Y); 如果是False，则为 col/row/(X,Y);
        :return: focus_rows * focus_cols * 2 显示格子行号和列号的列表 x,y
        """
        focus_rows += 2
        focus_cols += 2
        width -= 1
        height -= 1

        if width + left > max_row:
            width = max_row - left
        if height + top > max_col:
            height = max_col - top
        focus_rows -= 1
        focus_cols -= 1
        # focus_rows_list = [top]  # 行坐标
        # focus_cols_list = [left]  # 列坐标
        focus_rows_list = []  # 行坐标
        focus_cols_list = []  # 列坐标

        pre_grid_row = width // focus_rows
        grid_row_rem = width % focus_rows
        pre_grid_col = height // focus_cols
        grid_col_rem = height % focus_cols
        pre_grid_row = max(pre_grid_row, 1)
        pre_grid_col = max(pre_grid_col, 1)
        data_i = 0
        for i in range(1, focus_rows):
            if grid_row_rem - data_i > 0:
                data_i += 1
            focus_rows_list.append(i * pre_grid_row + left + data_i)
        # focus_rows_list.append(width + left)

        data_i = 0
        for i in range(1, focus_cols):
            if grid_col_rem - data_i > 0:
                data_i += 1
            focus_cols_list.append(i * pre_grid_col + top + data_i)

        # focus_cols_list.append(height + top)
        X, Y = np.meshgrid(focus_rows_list, focus_cols_list)
        row_col = np.stack([X, Y], axis=-1)
        if re_row_col:
            return row_col.tolist()
        else:
            return row_col.transpose(1, 0, 2).tolist()

    @staticmethod
    def SlideOilArray(left: int, top: int, width: int, height: int, max_row: int, max_col: int, focus_rows: int, focus_cols: int, re_row_col: bool = False) -> list[list[int]]:
        """
        :param max_col: 最大格子数    薄片列数
        :param max_row: 最小格子数    薄片行数
        :param left: 起始位置格子列号
        :param top:  起始位置格子行号
        :param width: 格子宽度 平扫的列数    扫描区域
        :param height: 格子高度 平扫的行数   扫描区域
        :param focus_rows: 定焦点行数    # 打点
        :param focus_cols: 定焦点列数    # 打点
        :param re_row_col: 返回格式是否为先行后列  # 如果是True，则为 row/col/(X,Y); 如果是False，则为 col/row/(X,Y);
        :return: focus_rows * focus_cols * 2 显示格子行号和列号的列表 x,y
        """
        # focus_rows += 2
        # focus_cols += 2
        width -= 1
        height -= 1

        if width + left > max_row:
            width = max_row - left
        if height + top > max_col:
            height = max_col - top
        focus_rows -= 1
        focus_cols -= 1
        focus_rows_list = [top]  # 行坐标
        focus_cols_list = [left]  # 列坐标
        # focus_rows_list = []  # 行坐标
        # focus_cols_list = []  # 列坐标

        pre_grid_row = height // focus_rows
        grid_row_rem = height % focus_rows
        pre_grid_col = width // focus_cols
        grid_col_rem = width % focus_cols

        data_i = 0
        for i in range(1, focus_rows):
            if grid_row_rem - data_i > 0:
                data_i += 1
            focus_rows_list.append(i * pre_grid_row + top + data_i)
        focus_rows_list.append(height + top)

        data_i = 0
        for i in range(1, focus_rows):
            if grid_col_rem - data_i > 0:
                data_i += 1
            focus_cols_list.append(i * pre_grid_col + left + data_i)

        focus_cols_list.append(width + left)
        X, Y = np.meshgrid(focus_cols_list, focus_rows_list)
        row_col = np.stack([X, Y], axis=-1)
        if re_row_col:
            return row_col.tolist()
        else:
            return row_col.transpose(1, 0, 2).tolist()

    @staticmethod
    def SlideFocusingPoints(left: int, top: int, width: int, height: int, max_row: int, max_col: int, focus_rows: int,
                        focus_cols: int, re_row_col: bool = False)-> list[list[int]]:
        arrays: list[list[list[int]]] = SlidePointUtils.SlideFocusArray(left, top, width, height, max_row, max_col, focus_rows, focus_cols, re_row_col)
        points: list[list[int]] = []
        models: list[list[int]] = []
        middle: list[list[int]] = []
        border: list[list[int]] = []
        temp  : list[list[int]]
        l_temp: list[list[int]]
        r_temp: list[list[int]]
        l_middle: list[list[int]] = []
        r_middle: list[list[int]] = []
        l_border: list[list[int]] = []
        r_border: list[list[int]] = []
        length: int

        _array = arrays[1: -1]
        for index, item in enumerate(_array):
            temp = item[1:-1][::]
            length = len(temp)
            center = length // 2
            l_middle.append(temp[center::][::] )
            r_middle.append(temp[0:center][::] if len(temp[0:center]) < 2 else temp[0:center][::-1])
            l_border.append([item[-1]])
            r_border.append([item[0]])

        temp = arrays[0][1:-1][::]
        length = len(temp)
        center = length // 2
        l_middle.append(temp[center::][::])
        r_middle.append(temp[0:center][::] if len(temp[0:center]) < 2 else temp[0:center][::-1])
        l_border.append([arrays[0][-1]])
        r_border.append([arrays[0][0]])

        temp = arrays[-1][1:-1][::]
        length = len(temp)
        center = length // 2
        l_middle.append(temp[center::][::])
        r_middle.append(temp[0:center][::] if len(temp[0:center]) < 2 else temp[0:center][::-1])
        l_border.append([arrays[-1][-1]])
        r_border.append([arrays[-1][0]])

        for index in range(len(l_middle)):
            middle.extend(l_middle[index])

        for index in range(len(r_middle)):
            middle.extend(r_middle[index])

        for index in range(len(l_border)):
            middle.extend(l_border[index])

        for index in range(len(r_border)):
            middle.extend(r_border[index])

        # l_points: list[list[int]] = models[0: focus_rows + 1][::-1]
        # r_points: list[list[int]] = models[focus_rows + 1::][::-1]
        # points = np.concatenate((r_points, l_points)).tolist()
        return middle

    @staticmethod
    def SlideOilDropingPoints(left: int, top: int, width: int, height: int, max_row: int, max_col: int, drop_rows: int, drop_cols: int) -> list[list[int]]:
        # _focus_rows : int = min(4, max(1, drop_rows))
        _focus_cols: int = min(9, max(1, drop_cols))
        point_r: int = _focus_cols + 2
        if point_r % 2 == 0:
            point_r += 1
        arrays: list[list[list[int]]] = SlidePointUtils.SlideOilArray(left, top, width, height, max_row, max_col, point_r, point_r)
        maxlength: int = len(arrays)
        index: int = maxlength // 2
        if maxlength % 2 == 0:
            index += 1
        maxlength = len(arrays[index])
        begin: int = maxlength // 2 - abs(drop_cols) // 2
        if begin == 0:
            begin += 1
        elif begin % 2 == 0:
            begin -= 1
        end: int = begin + abs(drop_cols)
        points: list[list[list[int]]]
        try:
            points = arrays[index][begin: end]
        except Exception as e:
            begin = maxlength // 2
            points = arrays[index][begin: min(begin + abs(drop_cols) // 2, maxlength)]
        middle: list[int] = points[0]
        return points, middle

    @staticmethod
    def SlideAnointingPoints(left: int, top: int, width: int, height: int, max_row: int, max_col: int, drop_rows: int, drop_cols: int) -> list[list[int]]:
        _focus_rows : int = min(4, max(1, drop_rows))
        _focus_cols : int = min(10, max(1, drop_cols))
        arrays: list[list[list[int]]] = SlidePointUtils.SlideFocusArray(left, top, width, height, max_row, max_col, _focus_rows, _focus_cols)
        models2_: np.ndarray=np.transpose(np.stack(arrays, axis=0), axes=[1,0,2]).tolist()
        maxLength: int = len(models2_)
        array: list[list[int]]
        models1: list[list[int]] = []
        models2: list[list[int]] = []
        for index, item in enumerate(arrays):
            if index % 2 == 0:
                models1.extend(item[::])
            else:
                models1.extend(item[::-1])
        if _focus_rows % 2 == 0:
            for index, item in enumerate(models2_):
                if index % 2 == 0:
                    models2.extend(item[::-1])
                else:
                    models2.extend(item[::])
        else:
            index = 0
            while maxLength >= 1:
                item = models2_[maxLength - 1]
                if index % 2 == 0:
                    models2.extend(item[::-1])
                else:
                    models2.extend(item[::])
                index += 1
                maxLength -= 1


        return models1, models2



    @staticmethod
    def SlideScanningPoints(begin_row: int, begin_col: int, row_number: int, col_number: int, max_row: int, max_col: int, is_row_s_line: bool = True) -> list[list[int]]:
        if is_row_s_line:
            return SlidePointUtils.SlideMoveRowArray(begin_row, begin_col, row_number, col_number, max_row, max_col)
        else:
            return SlidePointUtils.SlideMoveColArray(begin_row, begin_col, row_number, col_number, max_row, max_col)

    @staticmethod
    def MicronucleusScanningArray(begin_row: int, begin_col: int, row_number: int, col_number: int, max_row: int, max_col: int, focus_rows: int, focus_cols: int) -> list[list[int]]:
        RowNumber: int
        ColNumber: int
        MinRowNumber: int = 1
        MinColNumber: int = 1
        FocusColNumber: int = 5
        max_row_number: int = max(MinRowNumber, min(40, max_row))
        max_col_number: int = max(MinColNumber, min(80, max_col))
        begin_row_number: int = max(MinRowNumber, min(begin_row, max_row_number))
        begin_col_number: int = max(MinColNumber, min(begin_col, max_col_number))
        slide_row_number: int = max(MinRowNumber, min(row_number, max_row_number - begin_row_number))
        slide_col_number: int = max(MinColNumber, min(col_number, max_col_number - begin_col_number))
        col_step_number: int = slide_col_number // 5
        col_begin_Numbers: list[int] = [i for i in range(0, FocusColNumber)]
        if col_step_number <= 0:
            col_step_number = 1

        points: list[list[int]] = []
        for col_index in range(0, len(col_begin_Numbers), 1):
            col_begin_number = col_begin_Numbers[col_index]
            piece_array: list[list[int]] = []
            b_col: int = begin_col_number + col_step_number * col_begin_number
            e_col: int = begin_col_number + col_step_number * (col_begin_number + 1)
            for col in range(b_col, e_col + 1):
                row_list: list[int] = []
                if col % 2 == 0:
                    if begin_row_number % 2 == 0:
                        for row in range(begin_row_number, begin_row_number + slide_row_number + 1):
                            row_list.append([row, col])
                    else:
                        for row in range(begin_row_number + slide_row_number, begin_row_number - 1, -1):
                            row_list.append([row, col])
                    piece_array.append(row_list)
                else:
                    if begin_row_number % 2 == 0:
                        for row in range(begin_row_number + slide_row_number, begin_row_number - 1, -1):
                            row_list.append([row, col])
                    else:
                        for row in range(begin_row_number, begin_row_number + slide_row_number + 1):
                            row_list.append([row, col])
                    piece_array.append(row_list[::-1])
            points.append(piece_array)

        return points


    @staticmethod
    def SlideMoveRowArray(begin_row: int, begin_col: int, row_number: int, col_number: int, max_row: int, max_col: int) -> list[list[int]]:
        points: list[list[int]] = []
        MinRowNumber: int = 1
        MinColNumber: int = 1
        MaxRowNumber: int = max_row
        MaxColNumber: int = max_col
        RowNumber   : int
        ColNumber   : int
        max_row_number: int = max(MinRowNumber, min(40, MaxRowNumber))
        max_col_number: int = max(MinColNumber, min(80, MaxColNumber))
        begin_row_number: int = max(MinRowNumber, min(begin_row, max_row_number))
        begin_col_number: int = max(MinColNumber, min(begin_col, max_col_number))
        slide_row_number: int = max(MinRowNumber, min(row_number, max_row_number))
        slide_col_number: int = max(MinColNumber, min(col_number, max_col_number))
        for RowNumber in range(begin_row_number, begin_row_number + slide_row_number):
            if begin_row_number % 2 == 0:
                if RowNumber % 2 == 0:
                    ColNumber = begin_col_number
                    while ColNumber < begin_col_number + slide_col_number:
                        points.append([RowNumber, ColNumber])
                        ColNumber += 1
                else:
                    ColNumber = begin_col_number + slide_col_number - 1
                    while ColNumber >= begin_col_number:
                        points.append([RowNumber, ColNumber])
                        ColNumber -= 1
            else:
                if RowNumber % 2 != 0:
                    ColNumber = begin_col_number
                    while ColNumber < begin_col_number + slide_col_number:
                        points.append([RowNumber, ColNumber])
                        ColNumber += 1
                else:
                    ColNumber = begin_col_number + slide_col_number - 1
                    while ColNumber >= begin_col_number:
                        points.append([RowNumber, ColNumber])
                        ColNumber -= 1
        return points

    @staticmethod
    def SlideMoveColArray(begin_row: int, begin_col: int, row_number: int, col_number: int, max_row: int, max_col: int) -> list[list[int]]:
        points: list[list[int]] = []
        MinRowNumber: int = 1
        MinColNumber: int = 1
        MaxRowNumber: int = max_row
        MaxColNumber: int = max_col
        RowNumber   : int
        ColNumber   : int
        max_row_number: int = max(MinRowNumber, min(40, MaxRowNumber))
        max_col_number: int = max(MinColNumber, min(80, MaxColNumber))
        begin_row_number: int = max(MinRowNumber, min(begin_row, max_row_number))
        begin_col_number: int = max(MinColNumber, min(begin_col, max_col_number))
        slide_row_number: int = max(MinRowNumber, min(row_number, max_row_number))
        slide_col_number: int = max(MinColNumber, min(col_number, max_col_number))
        for ColNumber in range(begin_col_number, begin_col_number + slide_col_number):
            if begin_col_number % 2 == 0:
                if ColNumber % 2 == 0:
                    RowNumber = begin_row_number
                    while RowNumber < begin_row_number + slide_row_number:
                        points.append([RowNumber, ColNumber])
                        RowNumber += 1
                else:
                    RowNumber = begin_row_number + slide_row_number - 1
                    while RowNumber >= begin_row_number:
                        points.append([RowNumber, ColNumber])
                        RowNumber -= 1
            else:
                if ColNumber % 2 != 0:
                    RowNumber = begin_row_number
                    while RowNumber < begin_row_number + slide_row_number:
                        points.append([RowNumber, ColNumber])
                        RowNumber += 1
                else:
                    RowNumber = begin_row_number + slide_row_number - 1
                    while RowNumber >= begin_row_number:
                        points.append([RowNumber, ColNumber])
                        RowNumber -= 1

        return points
