import numpy as np
import os
import rospy
from math import acos, degrees,tan,atan,sqrt,sin,cos
from scipy.spatial.transform import Rotation as R

#求向量的模
def calculate_distance(point1, point2):
    return np.linalg.norm(np.array(point1) - np.array(point2))

#计算焊缝向量与xy平面夹角 用于判断是平缝还是竖缝
def calculate_angle_with_xy_plane(point1,point2):
    # 计算方向向量
    dir_vector = np.array([point2[0] - point1[0], point2[1] - point1[1], point2[2] - point1[2]])
    
    # 计算方向向量在 xy 平面上的投影
    proj_vector = np.array([point2[0] - point1[0], point2[1] - point1[1], 0])
    
    # 计算夹角
    angle = acos(np.dot(dir_vector, proj_vector) / (np.linalg.norm(dir_vector) * np.linalg.norm(proj_vector)))
    angle_deg = degrees(angle)

    return angle_deg


# 从文件中读取焊缝起点和终点，并分为平缝和竖缝
def read_hanfeng_from_point_txt(file_path):

    data_ping, data_shu = [],[]

    with open(file_path, 'r') as file:
        # 逐行读取文件内容
        lines = file.readlines()
    flag_sequence = 0
    for line in lines:
        flag_sequence += 1
        # 去除行尾的换行符并按'/'分割每一行
        points_str = line.strip().split('/')
        
        point1_str = points_str[0].split(',')
        point2_str = points_str[1].split(',')
        
        # 转换字符串为浮点数列表，构造三维点
        point1 = [float(coord) for coord in point1_str]
        point2 = [float(coord) for coord in point2_str]

        angle = calculate_angle_with_xy_plane(point1,point2)
        
        if abs(angle) <  rospy.get_param("ping_sta"):#用于判断平缝的角度
            data_ping.append([point1, point2, flag_sequence])
        else:
            data_shu.append([*sorted([point1, point2], key=lambda p: p[2]), flag_sequence]) 

        data = data_ping + data_shu

    return data_ping, data_shu


def sort_welds_by_distance_ping(data_ping, reference_point):
    """根据与参考点的距离对焊缝进行排序"""
    sorted_data_ping = []#一定放for外
    for i in range(len(data_ping)):
        # 计算起点到参考点的距离并排序[[起点与参考点距离，终点与参考点距离，起点坐标，终点坐标，焊缝序号（与points文件中顺序对应）],[],[]....]
        data_with_distances = [[calculate_distance(start, reference_point),calculate_distance(end, reference_point), start, end,flag_sequence] for start, end,flag_sequence in data_ping]
        for i in range(len(data_with_distances)):
            if data_with_distances[i][0] > data_with_distances[i][1]:#若起点比终点离参考点更远 则互换起始点 且将第一个元素变为最近的点（后面用lambda针对第一个元素大小排序）
                data_with_distances[i][0] = data_with_distances[i][1]
                tem = data_with_distances[i][2]
                data_with_distances[i][2] = data_with_distances[i][3]
                data_with_distances[i][3] = tem
        data_with_distances.sort(key=lambda x: x[0])#将水平焊缝（起点是离机器人近的那一端）按照起点离参考点的距离排序

        # 初始化结果和当前终点
        sorted_data_ping.append(data_with_distances.pop(0)[-3:])  # 取出data_with_distances第一个元素的 起点坐标 终点坐标  焊缝序号
        #reference_point = sorted_data_ping[-1][1] #参考点变更为 sorted_data_ping中的最后一个点   即寻找离当前焊缝终点最近的

        data_ping = [[start, end,flag_sequence] for distances1,distances2, start,end,flag_sequence in data_with_distances]#从弹出已经排好的点的数组重新更新被处理列表
        
        #将起始点位置交换回来，保证平缝焊接方向一致   
        # for i in range(len(sorted_data_ping)):
        #     sorted_data_ping[i][0], sorted_data_ping[i][1] = sorted_data_ping[i][1], sorted_data_ping[i][0]
            
    return sorted_data_ping  #焊接方向最终是由参考点近端向远端焊接  顺序为先找离参考点最近的 然后找其次的


# def sort_welds_by_distance_shu(data_shu, reference_point):
#     """根据与参考点的距离对焊缝进行排序"""
#     sorted_data_shu = []
#     for i in range(len(data_shu)):
#         # 计算起点到参考点的距离并排序
#         data_with_distances = [[calculate_distance(start, reference_point), start, end ,flag_sequence] for start, end ,flag_sequence in data_shu]
        
#         data_with_distances.sort(key=lambda x: x[0])

#         # 初始化结果和当前终点
#         sorted_data_shu.append(data_with_distances.pop(0)[-3:])
#         reference_point = sorted_data_shu[-1][1]
#         data_shu = [[start, end ,flag_sequence] for distances, start,end ,flag_sequence in data_with_distances]
#     return sorted_data_shu

def compute_pose_R(fangxiang, hanfeng):
    """wg根据计算出的焊接时z轴负方向的向量(fangxiang)和由起点指向终点的向量(hanfeng)计算旋转矩阵""" #得到的是fangxiang向量相对于基坐标系原点的姿态变换矩阵 多了个绕x转180的变换
    x, y, z = fangxiang

    # 计算旋转角度
    rotx = -np.arctan2(y, z)#投影到yz平面的的夹角
    roty = np.arctan2(x, np.sqrt(y**2 + z**2))#向量和yz面的夹角

    # 构造旋转矩阵 rot x y   先绕x转不影响向量和yz面的夹角？
    A = np.array([[1, 0, 0],
                [0, np.cos(rotx), -np.sin(rotx)],
                [0, np.sin(rotx), np.cos(rotx)]])
    
    B = np.array([[np.cos(roty), 0, np.sin(roty)],
                [0, 1, 0],
                [-np.sin(roty), 0, np.cos(roty)]])
    
    bb = np.matmul(hanfeng, np.matmul(A, B))#先转到XOZ  再转到X  相当于通过将方向向量转到z轴上的方式 让焊缝向量转到XOY平面 通过方向向量和焊缝向量的正交关系求出向量在Z轴上的转角
    # 区分平缝竖缝

    rotz = np.arctan2(-bb[1], -bb[0])
    


    # 构造旋转矩阵 rot z x
    C = np.array([[np.cos(rotz), -np.sin(rotz), 0],
                [np.sin(rotz), np.cos(rotz), 0],
                [0, 0, 1]])
    D = np.array([[1, 0, 0],
                    [0, np.cos(np.pi), -np.sin(np.pi)],
                    [0, np.sin(np.pi), np.cos(np.pi)]])

    #R_mat = np.matmul(A, np.matmul(B, np.matmul(C, D)))
    R_mat = np.matmul(A, np.matmul(B, C))
    #A*(B*(C*D))              x*y*z*x(180)
    return R_mat

def run():
    result=[]

    # 定义参考点，排序
    #reference_point = (1172.85077147, -1.50259925, 668.30298144)
    reference_point = (0.0,0.0, 0.0)

    file_path = rospy.get_param("folder_path")
    file_path_points = os.path.join(file_path, 'points.txt')
    file_path_result = os.path.join(file_path, 'result.txt')

    data_ping, data_shu= read_hanfeng_from_point_txt(file_path_points)


    # 对焊缝排序
    sorted_data_ping = sort_welds_by_distance_ping(data_ping, reference_point)
    # if len(data_ping) > 0:
    #     a = tuple(sorted_data_ping[-1][1])
    # else:
    #     a = reference_point
    # sorted_welds_shu = sort_welds_by_distance_shu(data_shu, a)
    sorted_welds = sorted_data_ping# + sorted_welds_shu  #[[起点，终点，序号],[],[]。。。。]
    
    #传递焊接顺序(points读入时的编号，从零开始)
    flag_sequence = [flag_sequence for start,end ,flag_sequence in sorted_welds]
    rospy.set_param('welding_sequence',flag_sequence)

    sorted_welds_withnoflag = [[start,end]for start,end ,flag_sequence in sorted_welds]

    # with open(file_path_points_guihua, "w") as file:
    #     for start, end in sorted_welds_withnoflag:
    #         # 将每一对起点和终点转换为字符串，并用逗号连接，最后以换行符分隔不同的焊缝对
    #         line = "{},{},{}".format(start[0], start[1], start[2]) + "/" + "{},{},{}".format(end[0], end[1], end[2]) + "\n"
    #         file.write(line)
    # rospy.loginfo("Welding sequence calculation completed")



# 计算位姿 ########################################################################################################
    if len(sorted_welds_withnoflag)!=2:
        rospy.loginfo("焊缝数量错误！！！！")
        exit(0)
    
    point1=sorted_welds_withnoflag[0]
    point2=sorted_welds_withnoflag[1]

    # middle1=[(point1[0][0]+point1[1][0])/2,(point1[0][1]+point1[1][1])/2,(point1[0][2]+point1[1][2])/2]
    # middle2=[(point2[0][0]+point2[1][0])/2,(point2[0][1]+point2[1][1])/2,(point2[0][2]+point2[1][2])/2]
    
    middle1=[(point1[0][0]+point1[1][0])/2,(point1[0][1]+point1[1][1])/2,0]
    middle2=[(point2[0][0]+point2[1][0])/2,(point2[0][1]+point2[1][1])/2,0]#不计算z的偏移 就是相对于水平的旋转

    hanfeng1=[point1[1][0]-point1[0][0],point1[1][1]-point1[0][1],point1[1][2]-point1[0][2]]
    hanfeng2=[point2[1][0]-point2[0][0],point2[1][1]-point2[0][1],point2[1][2]-point2[0][2]]
    #sorted_welds    #[[起点，终点，序号],[],[]。。。。]


    faxiang=[middle2[0]-middle1[0],middle2[1]-middle1[1],middle2[2]-middle1[2]]
    shuzhi=np.cross(faxiang,hanfeng1)#向量叉乘 

    faxiang/= np.linalg.norm(faxiang)  # 单位化
    shuzhi /= np.linalg.norm(shuzhi)  # 单位化
    
    #ang_md=calculate_angle_with_xy_plane(middle1,middle2)

    # if(point1[0][0]<0 and point2[0][0]<0):
    #     fangxiang=faxiang+shuzhi*5.6 #arctan(4)=76度
    # else:
    #     fangxiang=faxiang-shuzhi*5.6 #arctan(4)=76度

    if(point1[0][0]<0 and point2[0][0]<0):
        fangxiang=faxiang+shuzhi*5.6 #arctan(4)=76度
    else:
        fangxiang=faxiang-shuzhi*5.6 #arctan(4)=76度

    mat=compute_pose_R(fangxiang,hanfeng1)
    q = R.from_matrix(mat).as_quat()#应该是RPY转四元数
    result.append(("s", point1[0],point1[1], q, q))


    # if(point1[0][0]<0 and point2[0][0]<0):
    #     fangxiang=-faxiang+shuzhi*5.6 #arctan(4)=76度
    # else:
    #     fangxiang=-faxiang-shuzhi*5.6 #arctan(4)=76度

    if(point1[0][0]<0 and point2[0][0]<0):
        fangxiang=faxiang+shuzhi*5.6 #arctan(4)=76度
    else:
        fangxiang=-faxiang-shuzhi*5.6 #arctan(4)=76度
        
    mat=compute_pose_R(fangxiang,hanfeng1)
    q = R.from_matrix(mat).as_quat()#应该是RPY转四元数
    result.append(("s", point2[0],point2[1], q, q))


    # 打开文件准备写入
    with open(file_path_result, "w") as file:
        for group in result:
            # 对于每个数据组，将每个部分用逗号连接，然后在各部分间插入斜杠
            line = "/".join([",".join(map(str, sublist)) for sublist in group]) + "\n"
            file.write(line)


    rospy.loginfo("顺序与姿态规划完毕 0v0")


if __name__ == '__main__':    
    run()



    
   


   