#include "geocomputation.h"
#include "Stream/ugdefs.h"

#include "erkir/sphericalpoint.h"

GeoComputation::GeoComputation()
{

}

/*@brief 计算两点间球面距离
 * @param lon1(-180至180),lat1(-90到90) 经纬度点1(度)
 * @param lon2,lat3 经纬度点2(度)
 * @return 距离(m)
 */
double GeoComputation::getSphericalDistance(double lon1, double lat1, double lon2, double lat2)
{
    erkir::spherical::Point p1{ lat1, lon1 };
    erkir::spherical::Point p2{ lat2, lon2 };
    double distance = p1.distanceTo(p2);
    return distance;
}

/*@brief  根据起点坐标、方位角、距离,计算另一点坐标。
* startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180))
* bearing:方位角(0-360)(度)
* dist:两点之间距离(m)
*/
QPointF GeoComputation::getDestinationPoint(double lon1, double lat1, double bearing, double dist)
{
    erkir::spherical::Point p{ lat1, lon1 };
    auto dest = p.destinationPoint(dist, bearing); // 51.5135°N, 000.0983°W
    QPointF point(dest.longitude().degrees(),dest.latitude().degrees());
    return point;
}

/*@brief  根据起点坐标、方位角、距离,计算另一点坐标。
* 使用Vincenty's公式求解,使用WGS-84椭球
* startPoint:起始点地理坐标点(lat(-90到90),lon(-180,180))
* bearing:方位角(度)
* dist:两点之间距离(km)
*/
QPointF GeoComputation::computeOffsetGeoPosition(double lon1, double lat1, double bearing, double dist)
{
    QPointF endPoint;
    //角度转化为弧度
//    qreal lon1 = (fmod(startPoint.x()+540,360)-180.0)*PI/180;
    lon1 = lon1*PI/180.0;
    lat1 = lat1*PI/180.0;
    bearing = bearing*PI/180.0;
    dist = dist*1000;

    //WGS-84椭球参数
    double flat = 298.257223563;
    double a = 6378137.0;
    double b = 6356752.314245;
    //开始求解坐标
    double f = 1/flat;
    double sb = sin(bearing);
    double cb = cos(bearing);
    double tu1 = (1-f)*tan(lat1);
    double cu1 = 1/sqrt((1+tu1*tu1));
    double su1 = tu1*cu1;
    double s2 = atan2(tu1, cb);
    double sa = cu1*sb;
    double csa = 1-sa*sa;
    double us = csa*(a*a - b*b)/(b*b);
    double A = 1+us/16384*(4096+us*(-768+us*(320-175*us)));
    double B = us/1024*(256+us*(-128+us*(74-47*us)));
    double s1 = dist/(b*A);
    double s1p = 2*PI;


    double cs1m = 0.0;
    double ss1 = 0.0;
    double cs1 = 0.0;
    double ds1 = 0.0;

    while (abs(s1-s1p) > 1e-12)
    {
        cs1m = cos(2*s2+s1);
        ss1 = sin(s1);
        cs1 = cos(s1);
        ds1 = B*ss1*(cs1m+B/4*(cs1*(-1+2*cs1m*cs1m)- B/6*cs1m*(-3+4*ss1*ss1)*(-3+4*cs1m*cs1m)));
        s1p = s1;
        s1 = dist/(b*A)+ds1;
    }

    double t = su1*ss1-cu1*cs1*cb;
    double lat2 = atan2(su1*cs1+cu1*ss1*cb, (1-f)*sqrt(sa*sa + t*t));
    double l2 = atan2(ss1*sb, cu1*cs1-su1*ss1*cb);
    double c = f/16*csa*(4+f*(4-3*csa));
    double l = l2-(1-c)*f*sa* (s1+c*ss1*(cs1m+c*cs1*(-1+2*cs1m*cs1m)));
    double lon2 = lon1+l;

    endPoint.setX(lon2*180/PI);
    endPoint.setY(lat2*180/PI);
    return endPoint;
}

//显示坐标转地图坐标
UGPoint2D GeoComputation::DPtoMP(UGMap *pMap, const QPoint &point)
{
    UGDrawCache &drawing = pMap->GetDrawing()->m_DrawCache;
    UGPoint DP(point.x(), point.y());
    UGPoint2D LP(0,0);
    drawing.DPtoLP(&DP, &LP, 1);

    UGPoint2D MP(0, 0);

    pMap->GetDrawing()->m_DrawParam.LPtoMP(LP, MP);

    return MP;
}