import math

import numpy as np

import model

model = model.Model()
u0 = model.u0
v0 = model.v0
f = model.f
H = model.H
dx = model.dx
dy = model.dy
alpha = model.alpha
beta = model.beta
q = model.q
x_change = model.x
y_change = model.y
"""
计算图像中一点到车辆坐标的距离
参数：点在图像中的坐标x、y，相机的外部偏转角参数alpha、beta
返回值：点在车辆坐标系下的二维坐标
"""
def calc_distance(x, y, alpha, beta):
    # print(f"q={q}")
    Xp = (x - u0) * dx
    Yp = -(y - v0) * dy
    Xp1 = (x - u0) * dx
    Yp1 = -(y - v0) * dy
    Xp = Xp1 * math.cos(q) + Yp1 * math.sin(q)
    Yp = -Xp1 * math.sin(q) + Yp1 * math.cos(q)
    # print(f"Yp1 = {Yp1},Yp = {Yp}")
    # print(f"Xp1 = {Xp1},Xp = {Xp}")
    sq = math.sqrt(f * f + Yp * Yp)
    eta = math.atan(Yp / f)
    gamma = math.atan(1 / (math.tan(alpha) * math.tan(beta)))
    seta = math.atan(1/math.sqrt(pow(math.tan(beta), 2) + 1 / pow(math.tan(alpha), 2)))
    MP = H * math.fabs(Xp) / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))
    OM = H / math.tan(seta + eta)
    epsilon = math.atan((H * Xp / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))) / OM)
    d = math.sqrt(MP ** 2 + OM ** 2)
    Xw = d * math.cos(gamma + epsilon) - 0*model.x
    Yw = -d * math.sin(gamma + epsilon) - 0*model.y
    return Xw, Yw

"""
计算车辆坐标系下某点在图像中的位置
参数：点在车辆坐标系下的坐标Xw、Yw，相机的外部偏转角参数alpha、beta
返回值：点在图像中的二维坐标
"""
def calc_distance2(Xw, Yw, alpha, beta):
    d = math.sqrt((Xw - model.x) ** 2 + (Yw + model.y) ** 2)
    seta = math.atan(1 / math.sqrt(pow(math.tan(beta), 2) + 1 / pow(math.tan(alpha), 2)))
    gamma = math.atan(1 / (math.tan(alpha) * math.tan(beta)))
    # 计算组合角度
    angle = math.atan2(-Yw, Xw)  # 使用atan2处理所有象限
    # 解出epsilon
    epsilon = angle - gamma
    # 将结果调整到[-pi, pi]范围内
    epsilon = (epsilon + math.pi) % (2 * math.pi) - math.pi
    OM = math.fabs(d * math.cos(epsilon))
    MP = math.fabs(d * math.sin(epsilon))
    eta = math.atan(H / OM) - seta
    Yp1 = math.tan(eta) * f
    Xp1 = MP * math.sqrt(f ** 2 + Yp1 ** 2) * math.sin(seta + eta)/H
    if epsilon > 0:
        Xp1 = Xp1
    else:
        Xp1 = -Xp1
    Xp = Xp1 * math.cos(-q) + Yp1 * math.sin(-q)
    Yp = -Xp1 * math.sin(-q) + Yp1 * math.cos(-q)
    x = Xp / dx +u0
    y = -Yp / dy +v0
    return int(x), int(y)

# print(f"result: {calc_distance2(1291,-562 , alpha, beta)}")

"""
计算图像中一点距离地面的高度
参数：地面端点在图像中的坐标x_bot、y_bot，垂线上端点在图像中的坐标x_top、y_top，相机的外部偏转角参数alpha、beta
返回值：点距离地面的高度
"""
def calc_height(x_bot,y_bot,x_top,y_top,alpha,beta):
    Xp = (x_bot - u0) * dx
    Yp = -(y_bot - v0) * dy
    Xp1 = (x_bot - u0) * dx
    Yp1 = -(y_bot - v0) * dy
    Xp = Xp1 * math.cos(q) + Yp1 * math.sin(q)
    Yp = -Xp1 * math.sin(q) + Yp1 * math.cos(q)
    sq = math.sqrt(f * f + Yp * Yp)
    eta = math.atan(Yp / f)
    gamma = math.atan(1 / (math.tan(alpha) * math.tan(beta)))
    seta = math.atan(1/math.sqrt(pow(math.tan(beta), 2) + 1 / pow(math.tan(alpha), 2)))
    MP = H * math.fabs(Xp) / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))
    OM = H/math.tan(seta + eta)
    Yp1 = -(y_top - v0) * dy
    Xp1 = (x_top- u0) * dx
    Yp1 = -(y_top - v0) * dy
    Xp = Xp1 * math.cos(q) + Yp1 * math.sin(q)
    Yp = -Xp1 * math.sin(q) + Yp1 * math.cos(q)
    sq1 = math.sqrt(f * f + Yp * Yp)
    eta1 = math.atan(Yp / f)
    # print(f"Yp1: {Yp1},eta1: {eta1}")
    Zw = H - OM*math.tan(seta + eta1)
    return Zw

"""
计算图像中车辆坐标系Xw、Yw所对应的轴线
参数：
返回值：轴线上点在图像中的二维坐标x、y
"""
def calc_zeros_yto0(val):
    # 定义搜索范围和步长
    x_range = np.linspace(0, 1280, 1000)
    y_range = np.linspace(0, 960, 1000)

    # 存储解
    solutions = []
    tolerance = 1e-3  # 容忍误差

    # 网格搜索
    for x in x_range:
        for y in y_range:
            error = equations_yto0(x, y, val)
            if error < tolerance:
                solutions.append((x, y))

    # 去除近似重复的解
    unique_solutions = []
    for sol in solutions:
        # 检查是否与已找到的解近似
        is_unique = True
        for usol in unique_solutions:
            if np.allclose(sol, usol, atol=1):
                is_unique = False
                break
        if is_unique:
            unique_solutions.append(sol)
    x = []
    y = []
    # print("找到的解:")
    for sol in unique_solutions:
        # print(f"x = {sol[0]:.4f}, y = {sol[1]:.4f}")
        x.append(sol[0])
        y.append(sol[1])
    return x, y

def equations_yto0(x, y, val):
    Xp = (x - u0) * dx
    Yp = -(y - v0) * dy
    Xp1 = (x - u0) * dx
    Yp1 = -(y - v0) * dy
    Xp = Xp1 * math.cos(q) + Yp1 * math.sin(q)
    Yp = -Xp1 * math.sin(q) + Yp1 * math.cos(q)
    sq = math.sqrt(f * f + Yp * Yp)
    eta = math.atan(Yp / f)
    gamma = math.atan(1 / (math.tan(alpha) * math.tan(beta)))
    seta = math.atan(1/math.sqrt(pow(math.tan(beta), 2) + 1 / pow(math.tan(alpha), 2)))
    MP = H * math.fabs(Xp) / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))
    OM = H / math.tan(seta + eta)
    epsilon = math.atan((H * Xp / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))) / OM)
    d = math.sqrt(MP ** 2 + OM ** 2)
    Xw = d * math.cos(gamma + epsilon)
    Yw = -d * math.sin(gamma + epsilon)
    return (Yw - val)**2   # 误差平方和

"""
计算图像中车辆坐标系Yw=某一固定值所对应的轴线
参数：
返回值：轴线上点在图像中的二维坐标x、y
"""
def calc_zeros_xto0(val):
    # 定义搜索范围和步长
    x_range = np.linspace(0, 1280, 1000)
    y_range = np.linspace(0, 960, 1000)

    # 存储解
    solutions = []
    tolerance = 1e-2  # 容忍误差

    # 网格搜索
    for x in x_range:
        for y in y_range:
            error = equations_xto0(x, y, val)
            if error < tolerance:
                solutions.append((x, y))

    # 去除近似重复的解
    unique_solutions = []
    for sol in solutions:
        # 检查是否与已找到的解近似
        is_unique = True
        for usol in unique_solutions:
            if np.allclose(sol, usol, atol=1):
                is_unique = False
                break
        if is_unique:
            unique_solutions.append(sol)
    x = []
    y = []
    # print("找到的解:")
    for sol in unique_solutions:
        # print(f"x = {sol[0]:.4f}, y = {sol[1]:.4f}")
        x.append(sol[0])
        y.append(sol[1])
    return x, y

def equations_xto0(x, y, val):
    Xp = (x - u0) * dx
    Yp = -(y - v0) * dy
    Xp1 = (x - u0) * dx
    Yp1 = -(y - v0) * dy
    Xp = Xp1 * math.cos(q) + Yp1 * math.sin(q)
    Yp = -Xp1 * math.sin(q) + Yp1 * math.cos(q)
    sq = math.sqrt(f * f + Yp * Yp)
    eta = math.atan(Yp / f)
    gamma = math.atan(1 / (math.tan(alpha) * math.tan(beta)))
    seta = math.atan(1/math.sqrt(pow(math.tan(beta), 2) + 1 / pow(math.tan(alpha), 2)))
    MP = H * math.fabs(Xp) / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))
    OM = H / math.tan(seta + eta)
    epsilon = math.atan((H * Xp / (math.sqrt(f ** 2 + Yp ** 2) * math.sin(seta + eta))) / OM)
    d = math.sqrt(MP ** 2 + OM ** 2)
    Xw = d * math.cos(gamma + epsilon)
    Yw = -d * math.sin(gamma + epsilon)
    return (Xw-val)**2   # 误差平方和

