
import os,math
import numpy as np

# WGS-84经纬度转Web墨卡托
def wgs_to_mercator(x, y):
    y = 85.0511287798 if y > 85.0511287798 else y
    y = -85.0511287798 if y < -85.0511287798 else y

    x2 = x * 20037508.34 / 180.0
    y2 = math.log(math.tan((90.0 + y) * math.pi / 360.0)) / (math.pi / 180.0)
    
    #print( ' y:',y, "  before Log:",math.tan((90.0 + y) * math.pi / 360.0),  ' log:'  , math.log(math.tan((90.0 + y) * math.pi / 360.0)))
    y2 = y2 * 20037508.34 / 180.0
    return x2, y2
def mercator_to_wgs(x, y):
    """
    将墨卡托投影坐标转换为WGS-84经纬度坐标
    :param x: 墨卡托投影的X坐标
    :param y: 墨卡托投影的Y坐标
    :return: 经度（longitude）和纬度（latitude）
    """
    # 地球半径（米）
    R = 6378137.0
    # 墨卡托投影的X坐标转换为经度
    lon = x / R * 180.0 / math.pi
    # 墨卡托投影的Y坐标转换为纬度
    lat = math.atan(math.sinh(y / R)) * 180.0 / math.pi
    return lon, lat


def ImageCorToCamCor(p0,w=1920,h=1080):
    x,y=p0[0:2]
    return  x-w/2.,(h-y)-h/2.

def wgs84_to_gcj02(lat, lon):  
    """将 WGS-84 坐标转换为 GCJ-02 坐标 (高德地图坐标)"""  
    A = 6378245.0  # 长半轴  
    EE = 0.00669342162296594323  # 偏心率平方  
    if out_of_china(lat, lon):  
        return lat, lon  # 如果在中国以外，直接返回 WGS-84 坐标  

    # 坐标转换  
    dlat = transform_lat(lon - 105.0, lat - 35.0)  
    dlon = transform_lon(lon - 105.0, lat - 35.0)  
    radlat = lat / 180.0 * math.pi  
    magic = math.sin(radlat)  
    magic = 1 - EE * magic * magic  
    sqrt_magic = math.sqrt(magic)  
    dlat = (dlat * 180.0) / (A * (1 - EE) / (magic * sqrt_magic) * math.pi)  
    dlon = (dlon * 180.0) / (A / sqrt_magic * math.cos(radlat) * math.pi)  
    
    mg_lat = lat + dlat  
    mg_lon = lon + dlon  

    return mg_lat, mg_lon  

def out_of_china(lat, lon):  
    """检查坐标是否在中国以外"""  
    return lon < 72.004 or lon > 137.8347 or lat < 0.8293 or lat > 55.8271  

def transform_lat(lon, lat):  
    """辅助函数: 进行纬度转换"""  
    ret = (-100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat +   
           0.1 * lon * lat + 0.2 * math.sqrt(abs(lon)))  
    ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0  
    ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0  
    ret += (160.0 * math.sin(lat / 12.0 * PI) + 320.0 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0  
    return ret  

def transform_lon(lon, lat):  
    """辅助函数: 进行经度转换"""  
    ret = (300.0 + lon + 2.0 * lat + 0.1 * lon * lon +   
           0.1 * lon * lat + 0.1 * math.sqrt(abs(lon)))  
    ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0  
    ret += (20.0 * math.sin(lon * PI) + 40.0 * math.sin(lon / 3.0 * PI)) * 2.0 / 3.0  
    ret += (150.0 * math.sin(lon / 12.0 * PI) + 300.0 * math.sin(lon / 30.0 * PI)) * 2.0 / 3.0  
    return ret
    
def cam2word(p0,pUAV,yaw,delta=1.55e-3 * 4056.0/1920,pitch=-45,f=4.5,camH=50e3,igW=1920,igH=1080):
    
    pitch = pitch/180.0*np.pi
    sinp = np.sin(pitch );cosp= np.cos(pitch)
    p0_new = ImageCorToCamCor(p0,igW,igH)
    Xc0 = p0_new[0]*delta;Zc0 = p0_new[1]*delta;
    
    #(Zw0,Xw0)--相对于光心，X，Z并未校正到正东和正北。
    #f=4.5*f/24.00
    Zw0=camH*(  -f*sinp  + Zc0*cosp )/( f*cosp + Zc0*sinp)*1e-3
    Xw0= camH*Xc0/(f*cosp + Zc0*sinp)*1e-3
    #print(' %4.0f    %4.0f    %4.8f   %4.8f   %4.8f   %4.8f   f:%.2f'%( p0[0],p0[1],  Xc0, Zc0,Xw0,Zw0,f ) )
    #yaw定义为拍摄方向，即图片的高方位（Z方向）偏离正北的方向，北偏东为正。
    yaw_rad = yaw/180.0*np.pi
    siny=np.sin(yaw_rad);cosy=np.cos(yaw_rad)
    Zx0_rot = Xw0*cosy + Zw0*siny + pUAV[0]
    Zw0_rot = -Xw0*siny + Zw0*cosy + pUAV[1]
    

    return Zx0_rot,Zw0_rot

def location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84'):
    '''
        输入图像中点的X，Y坐标，及无人机相关信息、相机相关信息，输出该点的Wgs84经纬度坐标
        point--点在图像上的坐标，左上角为（0,0），X方向为宽度方向，Y方向为高度方向
        igW--图像的宽度
        igH--图像的高度
        PlanWgs84--无人机的Wgs84坐标，(lon,lat),(经度，纬度)
        PlanH--无人机拍照时的相对高度，用mm表示
        yaw--云台的yaw
        delta--单个像素的长度值，用mm表示。
        pitch--无人的pitch
        focal--真实焦距，用mm表示
    '''    
    PlanX,PlanY = wgs_to_mercator(PlanWgs84[0],PlanWgs84[1])
    #print('location:',PlanX,PlanY)
    #PlanX,PlanY--东西、南北方向的墨卡托投影坐标
    #print( 'line268:',point,PlanX,PlanY,yaw, delta,pitch,focal,PlanH,igW,igH )
    cor_world = cam2word( point,(PlanX,PlanY),yaw, delta,pitch,focal,PlanH,igW,igH)
    cor_world = mercator_to_wgs(cor_world[0], cor_world[1])
    if outFormat=='GCJ02' or outFormat=='gcj02':
        cor_world = wgs84_to_gcj02(cor_world[0], cor_world[1])  
    
    return cor_world
    
def locate_byMqtt(box,igW,igH,camParas,outFormat='wgs84'):
    #camParas--{'lon': 3479.8250608, 'lat': 3566.7630802, 'gpssingal': 4, 'satcount': 6896, 'alt': 3.256, 'hspeed': 86.0, 'vspeed': 4.447911, 'ysingal': 0, 'tsingal': 0, 'voltage': 24.971, 'flytime': 0, 'datetime': 1739315683895, 'yaw': 70.243252, 'roll': -0.89436062, 'pitch': 0.89897547, 'armed': 'false', 'mode': 'stabilize', 'distToHome': 7.132033, 'deviceid': 'THJSQ03A2302KSPYGJ2G', 'mileage': '0', 'altasl': 21.26, 'altasl2': -20.74, 'landing_target_x': 0, 'landing_target_y': 0, 'landing_target_z': 0}
    #模型输出的点的格式是-[(486, 264), (505, 264), (505, 290), (486, 290)]
    
    box_np = np.array(box);  
    point = int(np.mean( box_np[:,0] )) , int(np.mean( box_np[:,1] ))
    PlanWgs84 = (float(camParas['lon']),float(camParas['lat'])) #
    PlanH = float(camParas['alt'])#
    yaw = float(camParas['camerayaw'])
    #delta = camParas['']
    delta = 1.55e-3 * 4056.0/1920
    pitch = float(camParas['camerapitch'])
    #focal = camParas['']
    focal = 3.5 
    
    out = location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84')
    return out

if __name__=="__main__":
    srt="videos/DJI_20221220133918_0001_W_0.SRT"
    videoUrl = "videos/DJI_20221220133918_0001_W.MP4"
    imgOut= "videos/imgs"
    fpbeg=17273;fpend=17830
    nums = list(range(fpbeg,fpend,16))
    #generateNewSRT(srt)  
    #captureImages(videoUrl,nums,imgOut)    
    
    process(videoUrl,srt,nums,imW=1920,imH=1080,txtDir='videos/labels' )
    #draw_results()
    
    #rotate_example()
    #rotate_example3()