#include "frenet_planner.h"

#include <adc_tools/transfer.h>
#include <common/car_status.h>
#include <adc_tools/parameter_status.h>
//#include <decide_gps_00.h>
#include <adc_planner/lane_change_planner.h>

#include<Eigen/Dense>

using namespace std;
using namespace Eigen;

iv::decition::FrenetPlanner::FrenetPlanner(){
    this->planner_id = 1;
    this->planner_name = "Frenet";
    this->lidarGridPtr = NULL;
}

iv::decition::FrenetPlanner::~FrenetPlanner(){
    free(this->lidarGridPtr);
}


/**
 * @brief iv::decition::FrenetPlanner::getPath
 * 采用的基于frenet坐标系的最优局部路径生成方法,可实现从当前车道变换到另一车道之间的路径生成。还可实现车辆在路线旁起步的“有迹可循”。
 * 计算的是,在车辆到达 原始地图路径偏移offset距离的车道 之前,frenet下规划的路径。
 *
 * @param now_gps_ins          实时gps信息
 * @param gpsMapLine           地图数据点
 * @param PathPoint            地图路线中距离车辆位置最近的一个点的序号
 * @param offset               在车辆避障中,地图源路线所在车道 与 即将去往的车道 之间的距离差值。可以为负值。offset = -(roadNow - roadOri)*roadWidth
 * @param lidarGridPtr         激光雷达信息网格
 * @return                     返回一条车辆坐标系下的路径
 */
std::vector<iv::Point2D> iv::decition::FrenetPlanner::getPath(GPS_INS now_gps_ins, const std::vector<GPSData>& gpsMapLine, int PathPoint, double offset, iv::LidarGridPtr lidarGridPtr){
    this->roadNow = -1;
    this->now_gps_ins = now_gps_ins;
    this->gpsMapLine = gpsMapLine;
    this->PathPoint = PathPoint;
    this->lidarGridPtr = lidarGridPtr;
    LaneChangePlanner *lcp = new LaneChangePlanner();
    std::vector<iv::Point2D> gpsTrace = lcp->getPath(now_gps_ins,gpsMapLine,PathPoint,0,lidarGridPtr);
    delete lcp;
    double realSecSpeed = now_gps_ins.speed / 3.6;
    leftWidth = offset;
    rightWidth = offset;
    std::vector<iv::Point2D> trace = getGpsTrace_AfterCalcFrenetTrace(gpsTrace,realSecSpeed);
    return trace;
}

/**
 * @brief iv::decition::FrenetPlanner::chooseRoadByFrenet
 * 用frenet的方法对每条道路考察,选择一个最优的道路
 * @param now_gps_ins          实时gps信息
 * @param gpsMapLine           地图数据点
 * @param PathPoint            地图路线中距离车辆位置最近的一个点的序号
 * @param offsetL              在选择道路中,地图源路线左边的最大宽度。可以为负值。offsetL = -(roadSum - 1)*roadWidth
 * @param offsetR              在选择道路中,地图源路线右边的最大宽度。可以为非负值。offsetR = (roadOri - 0)*roadWidth
 * @param lidarGridPtr         激光雷达信息网格
 * @return
 */
int iv::decition::FrenetPlanner::chooseRoadByFrenet(GPS_INS now_gps_ins, const std::vector<GPSData>& gpsMapLine, int PathPoint, double offsetL, double offsetR, iv::LidarGridPtr lidarGridPtr,int roadNow){
    this->roadNow = roadNow;
    this->aimRoadByFrenet = -1;
    this->now_gps_ins = now_gps_ins;
    this->gpsMapLine = gpsMapLine;
    this->PathPoint = PathPoint;
    this->lidarGridPtr = lidarGridPtr;

    LaneChangePlanner *lcp = new LaneChangePlanner();
    std::vector<iv::Point2D> gpsTrace = lcp->getPath(now_gps_ins,gpsMapLine,PathPoint,0,lidarGridPtr);
    delete lcp;
    double realSecSpeed = now_gps_ins.speed / 3.6;
    leftWidth = offsetL;
    rightWidth = offsetR;
    std::vector<iv::Point2D> trace = getGpsTrace_AfterCalcFrenetTrace(gpsTrace,realSecSpeed);
    return aimRoadByFrenet;
}


/**
 * @brief iv::decition::FrenetPlanner::getGpsTrace_AfterCalcFrenetTrace
 * 进行frenet规划的总函数,还包括了规划前的一些准备工作,比如frenet坐标系建立、车辆起始状态等。
 * @param gpsTrace             地图路线上从PathPoint开始的600个点
 * @param realsecSpeed         实时车速 [m/s]
 * @return                     返回一条frenet规划后并转换到车辆坐标系下的路径
 */
std::vector<iv::Point2D> iv::decition::FrenetPlanner::getGpsTrace_AfterCalcFrenetTrace(const std::vector<iv::Point2D>& gpsTrace,double realsecSpeed){
    vector<Point2D> trace;
    vector<FrenetPoint> frenet_s;
    double stp=0.0;
    //把gpsTrace里的点全部转为frenet坐标系下的点,存储在frenet_s中。相当于frenet坐标系的S轴。
    FrenetPoint tmp={.x=gpsTrace[0].x,.y=gpsTrace[0].y,.s=0.0,.d=0.0};
    frenet_s.push_back(tmp);
    for(int i=1; i<gpsTrace.size(); ++i){
        stp+=iv::decition::GetDistance(gpsTrace[i-1],gpsTrace[i]);
        tmp={.x=gpsTrace[i].x,.y=gpsTrace[i].y,.s=stp,.d=0.0};
        frenet_s.push_back(tmp);
    }

    //求出车辆当前位置在frenet坐标系下的坐标
//    FrenetPoint car_now_at_frenet = XY2Frenet(0,0,gpsTrace);
    FrenetPoint car_now_at_frenet = getFrenetfromXY(0,0,gpsTrace,this->gpsMapLine,this->PathPoint,this->now_gps_ins);

    double c_s_speed = realsecSpeed * cos(car_now_at_frenet.tangent_Ang-M_PI/2);
    double c_d_speed = realsecSpeed * sin(car_now_at_frenet.tangent_Ang-M_PI/2);
    double realAcc = ServiceCarStatus.mfCalAcc;
    double c_s_dd = realAcc * cos(car_now_at_frenet.tangent_Ang-M_PI/2);
    double c_d_dd = realAcc * sin(car_now_at_frenet.tangent_Ang-M_PI/2);

    vector<Point2D> path=frenet_optimal_planning(car_now_at_frenet,frenet_s,c_s_speed,c_d_speed,c_d_dd);

    return path;
}


/**
 * @brief iv::decition::FrenetPlanner::frenet_optimal_planning
 * 对frenet规划出的路径进行后续操作,并选出损失最小的一条路径作为最优路径
 * @param car_now_frenet_point 车辆当前位置在frenet坐标系下的坐标
 * @param frenet_s             frenet坐标系的s轴
 * @param c_speed              车辆的纵向速度。沿s轴方向的速度。
 * @param c_d_d                车辆沿d方向的速度。
 * @param c_d_dd               车辆沿d方向的加速度。
 * @return                     返回一条frenet规划的最优路径
 */
vector<iv::Point2D> iv::decition::FrenetPlanner::frenet_optimal_planning(iv::decition::FrenetPoint car_now_frenet_point,
                                                          const std::vector<FrenetPoint>& frenet_s, double c_speed, double c_d_d, double c_d_dd){
    double s0 = car_now_frenet_point.s;
    double c_d = car_now_frenet_point.d;
    vector<iv::Point2D> gpsTrace;
    vector<Frenet_path> fplist=calc_frenet_paths(c_speed, c_d, c_d_d, c_d_dd, s0);  //frenet规划

    sort(fplist.begin(),fplist.end(),comp); //按损失度由小到大进行排序
    for(int i=0; i<fplist.size(); ++i){
        calc_global_single_path(fplist[i],frenet_s);
        if(check_single_path(fplist[i])){
            gpsTrace = frenet_path_to_gpsTrace(fplist[i]);
            aimRoadByFrenet = fplist[i].roadflag;
            return gpsTrace;
        }
    }
    return gpsTrace;

/*
//    calc_global_paths(fplist, frenet_s);    //生成frenet路径中每个点在车辆坐标系下的坐标
//    fplist = check_paths(fplist);  //检验计算出的每条路径
//    //找到损失最小的轨迹
//    double min_cost = (numeric_limits<double>::max)();
//    Frenet_path bestpath;
//    for(int i=0; i<fplist.size(); ++i){
//        if(min_cost > fplist[i].cf){
//            min_cost = fplist[i].cf;
//            bestpath = fplist[i];
//        }
//    }
//    gpsTrace = frenet_path_to_gpsTrace(bestpath);
//    aimRoadByFrenet = bestpath.roadflag;
//    return gpsTrace;
*/
}


/**
 * @brief iv::decition::FrenetPlanner::calc_frenet_paths
 * 正式规划出不同的frenet路径,并统计相应的损失度。单从车辆行驶的平滑性计算而得,后续需检测是否有障碍物。
 * @param c_speed              车辆的纵向速度。沿s轴方向的速度
 * @param c_d                  车辆的横向(d方向)偏移距离
 * @param c_d_d                车辆沿d方向的速度
 * @param c_d_dd               车辆沿d方向的加速度
 * @param s0                   车辆沿s方向的坐标
 * @return                     返回多条frenet路径
 */
vector<iv::decition::Frenet_path> iv::decition::FrenetPlanner::calc_frenet_paths(double c_speed, double c_d, double c_d_d, double c_d_dd, double s0){
    vector<iv::decition::Frenet_path> frenet_paths;
    int roadNum = round(abs((leftWidth-rightWidth)/ServiceParameterStatus.D_ROAD_W));   //roadNum为frenet算法的起始道路序号
    //采样,并对每一个目标配置生成轨迹
    for(double di=leftWidth; di<=rightWidth; di+=ServiceParameterStatus.D_ROAD_W,roadNum--){
        if(roadNum == this->roadNow)
            continue;
        //横向动作规划
        for(double Ti=ServiceParameterStatus.MINT; Ti<ServiceParameterStatus.MAXT; Ti+=ServiceParameterStatus.DT){
            Frenet_path fp;
            fp.roadflag = roadNum;
            //计算出关于目标配置di,Ti的横向多项式
            Quintic_polynomial lat_qp = Quintic_polynomial(c_d, c_d_d, c_d_dd, di, 0.0, 0.0, Ti);

            for(double i=0; i<Ti; i+=ServiceParameterStatus.D_POINT_T)
                fp.t.push_back(i);

            for(int i=0; i<fp.t.size(); ++i){
                fp.d.push_back(lat_qp.calc_point(fp.t[i]));
                fp.d_d.push_back(lat_qp.calc_first_derivative(fp.t[i]));
                fp.d_dd.push_back(lat_qp.calc_second_derivative(fp.t[i]));
                fp.d_ddd.push_back(lat_qp.calc_third_derivative(fp.t[i]));
            }

            //纵向速度规划 (速度保持)
            for(double tv=ServiceParameterStatus.TARGET_SPEED - ServiceParameterStatus.D_T_S * ServiceParameterStatus.N_S_SAMPLE;
                tv<(ServiceParameterStatus.TARGET_SPEED + ServiceParameterStatus.D_T_S * ServiceParameterStatus.N_S_SAMPLE);
                tv+=ServiceParameterStatus.D_T_S){
                Frenet_path tfp = fp;
                Quartic_polynomial lon_qp = Quartic_polynomial(s0, c_speed, 0.0, tv, 0.0, Ti);

                for(int i=0; i<fp.t.size(); ++i){
                    tfp.s.push_back(lon_qp.calc_point(fp.t[i]));
                    tfp.s_d.push_back(lon_qp.calc_first_derivative(fp.t[i]));
                    tfp.s_dd.push_back(lon_qp.calc_second_derivative(fp.t[i]));
                    tfp.s_ddd.push_back(lon_qp.calc_third_derivative(fp.t[i]));
                }

                //square of jerk
                double Jp = inner_product(tfp.d_ddd.begin(), tfp.d_ddd.end(), tfp.d_ddd.begin(), 0);
                //square of jerk
                double Js = inner_product(tfp.s_ddd.begin(), tfp.s_ddd.end(), tfp.s_ddd.begin(), 0);

                //square of diff from target speed
                double ds = pow((ServiceParameterStatus.TARGET_SPEED - tfp.s_d.back()),2);
                //横向的损失函数
                tfp.cd = ServiceParameterStatus.KJ * Jp + ServiceParameterStatus.KT * Ti + ServiceParameterStatus.KD * tfp.d.back() * tfp.d.back();
                //纵向的损失函数
                tfp.cv = ServiceParameterStatus.KJ * Js + ServiceParameterStatus.KT * Ti + ServiceParameterStatus.KD * ds;
                //总的损失函数为d 和 s方向的损失函数乘对应的系数相加
                tfp.cf = ServiceParameterStatus.KLAT * tfp.cd + ServiceParameterStatus.KLON * tfp.cv;

                frenet_paths.push_back(tfp);
            }
        }
    }
    return frenet_paths;
}


/**
 * @brief iv::decition::FrenetPlanner::calc_global_paths
 * 计算出每条frenet路径中轨迹点的x,y坐标。x,y坐标是轨迹点在车辆坐标系下的横纵坐标。
 * 部分函数参数在第一种计算XY坐标的方法中没有使用,但在第二种方法中会用到。
 * @param fplist               多条frenet路径
 * @param frenet_s             frenet坐标系的s轴
 * @return                     通过引用传递返回带有x,y值的多条frenet路径
 */
void iv::decition::FrenetPlanner::calc_global_paths(vector<Frenet_path>& fplist,const std::vector<FrenetPoint>& frenet_s){

    for(auto& fp:fplist){
        for(int i=0; i<fp.s.size(); ++i){
            double ix,iy;
//            Frenet2XY(&ix,&iy,fp.s[i],fp.d[i],frenet_s);  //第一种方法
            getXYfromFrenet(&ix,&iy,fp.s[i],fp.d[i],frenet_s,this->gpsMapLine,this->PathPoint,this->now_gps_ins);   //第二种方法

            fp.x.push_back(ix);
            fp.y.push_back(iy);
        }

        for(int i=0; i<(fp.x.size()-1); ++i){
            double dx = fp.x[i+1] - fp.x[i];
            double dy = fp.y[i+1] - fp.y[i];
            fp.yaw.push_back(atan2(dy,dx));
            fp.ds.push_back(sqrt(dx*dx + dy*dy));
        }

        fp.ds.push_back(fp.ds.back());
        fp.yaw.push_back(fp.yaw.back());

        for(int i = 0; i < (fp.yaw.size() - 1); ++i){
            fp.c.push_back((fp.yaw[i + 1] - fp.yaw[i]) / fp.ds[i]);
        }
    }
}

void iv::decition::FrenetPlanner::calc_global_single_path(Frenet_path &fp, const std::vector<FrenetPoint> &frenet_s){
    for(int i=0; i<fp.s.size(); ++i){
        double ix,iy;
        //            Frenet2XY(&ix,&iy,fp.s[i],fp.d[i],frenet_s);  //第一种方法
        getXYfromFrenet(&ix,&iy,fp.s[i],fp.d[i],frenet_s,this->gpsMapLine,this->PathPoint,this->now_gps_ins);   //第二种方法

        fp.x.push_back(ix);
        fp.y.push_back(iy);
    }

    for(int i=0; i<(fp.x.size()-1); ++i){
        double dx = fp.x[i+1] - fp.x[i];
        double dy = fp.y[i+1] - fp.y[i];
        fp.yaw.push_back(atan2(dy,dx));
        fp.ds.push_back(sqrt(dx*dx + dy*dy));
    }

    fp.ds.push_back(fp.ds.back());
    fp.yaw.push_back(fp.yaw.back());

    for(int i = 0; i < (fp.yaw.size() - 1); ++i){
        fp.c.push_back((fp.yaw[i + 1] - fp.yaw[i]) / fp.ds[i]);
    }
}


/**
 * @brief iv::decition::FrenetPlanner::check_paths
 * 对多条frenet路径进行检验,排除不符合要求的路径。
 * @param fplist               多条frenet路径
 * @return                     排除部分路径后的多条frenet路径
 */
vector<iv::decition::Frenet_path> iv::decition::FrenetPlanner::check_paths(const vector<Frenet_path>& fplist){
    vector<Frenet_path> okind;
    int i=0;
    int j=0;

    for(i=0; i<fplist.size(); ++i){
        cout<<"&&&&&&&&&&fplist[i].roadflag: "<<fplist[i].roadflag<<endl;
        for(j=0; j<fplist[i].s_d.size(); ++j){
            if(fplist[i].s_d[j]>ServiceParameterStatus.MAX_SPEED)       //最大速度检查
                goto ContinueFlag;
        }
        for(j=0; j<fplist[i].s_dd.size(); ++j){
            if(abs(fplist[i].s_dd[j])>ServiceParameterStatus.MAX_ACCEL) //最大加速度检查
                goto ContinueFlag;
        }
        for(j=30; j<fplist[i].c.size()-30; ++j){
            if(abs(fplist[i].c[j])>ServiceParameterStatus.MAX_CURVATURE)//最大曲率检查
                goto ContinueFlag;
        }
        if(!check_collision(fplist[i]))
            continue;
        okind.push_back(fplist[i]);
        ContinueFlag:continue;
    }
    return okind;
}


bool iv::decition::FrenetPlanner::check_single_path(const iv::decition::Frenet_path &fp){
    int j=0;

    cout<<"&&&&&&&&&&fp.roadflag: "<<fp.roadflag<<endl;
    for(j=0; j<fp.s_d.size(); ++j){
        if(fp.s_d[j]>ServiceParameterStatus.MAX_SPEED)       //最大速度检查
            return false;
    }
    for(j=0; j<fp.s_dd.size(); ++j){
        if(abs(fp.s_dd[j])>ServiceParameterStatus.MAX_ACCEL) //最大加速度检查
            return false;
    }
    for(j=30; j<fp.c.size()-30; ++j){
        if(abs(fp.c[j])>ServiceParameterStatus.MAX_CURVATURE)//最大曲率检查
            return false;
    }
    if(!check_collision(fp))
        return false;

    return true;
}


/**
 * @brief iv::decition::FrenetPlanner::check_collision
 * 检验frenet路径上是否有障碍物,调用的是改进的函数computeObsOnRoadByFrenet。
 * @param frenet_path          一条frenet路径
 * @param car_now_frenet_point 车辆当前位置在frenet坐标系下的坐标
 * @return                     在路径上有障碍物返回false,否则返回true。
 */
bool iv::decition::FrenetPlanner::check_collision(const iv::decition::Frenet_path &frenet_path){
    std::vector<Point2D> gpsTrace = frenet_path_to_gpsTrace(frenet_path);
    double obs=-1;
 //   iv::decition::DecideGps00().computeObsOnRoadByFrenet(this->lidarGridPtr,gpsTrace,obs,this->gpsMapLine,this->PathPoint,this->now_gps_ins);
    if(obs > 0 && obs < 30)
        return false;
    else
        return true;
}


/**
 * @brief iv::decition::FrenetPlanner::frenet_path_to_gpsTrace
 * 将frenet路径转换到车辆坐标系下。
 * @param frenet_path          一条frenet路径
 * @return                     一条车辆坐标系下的路径
 */
vector<iv::Point2D> iv::decition::FrenetPlanner::frenet_path_to_gpsTrace(const Frenet_path& frenet_path){
    vector<iv::Point2D> gpsTrace;
    for (int i=0; i<frenet_path.x.size(); ++i) {
        gpsTrace.push_back(Point2D(frenet_path.x[i],frenet_path.y[i]));
        gpsTrace[i].speed = sqrt(frenet_path.d_d[i]*frenet_path.d_d[i]+frenet_path.s_d[i]*frenet_path.s_d[i])*3.6;
    }
    return gpsTrace;
}


double iv::decition::FrenetPlanner::distance(double x1, double y1, double x2, double y2)
{
    return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}


//找出gpsTrace中距离(x,y)最近的一个点
int iv::decition::FrenetPlanner::ClosestWaypoint(double x, double y, const std::vector<Point2D>& gpsTrace)
{

    double closestLen = 100000; //large number
    int closestWaypoint = 0;

    for(int i = 1; i < gpsTrace.size(); i++)
    {
        double map_x = gpsTrace[i].x;
        double map_y = gpsTrace[i].y;
        double dist = distance(x,y,map_x,map_y);
        if(dist < closestLen)
        {
            closestLen = dist;
            closestWaypoint = i;
        }

    }
    return closestWaypoint;
}


 /* |==========================================================|
  * |         车辆坐标系与 frenet 坐标系互转的第一种方法。           |
  * |==========================================================| */
 // 车体坐标转frenet坐标。frenet坐标原点是 gpsTrace 中序号为0的点。
 // Transform from Cartesian x,y coordinates to Frenet s,d coordinates
iv::decition::FrenetPoint iv::decition::FrenetPlanner::XY2Frenet(double x, double y, const std::vector<iv::Point2D>& gpsTrace){
    int next_wp=ClosestWaypoint( x,  y,  gpsTrace);
    int prev_wp = next_wp-1;  //prev_wp代表在next_wp的前一个点计算坐标,能够保证frenet_s都是依次相加的。避免在next_wp计算frenet_s的话,可能出现减的情况。
//    if(next_wp == 0){
//        prev_wp  = gpsTrace.size()-1;
//    }

    double n_x = gpsTrace[next_wp].x-gpsTrace[prev_wp].x;
    double n_y = gpsTrace[next_wp].y-gpsTrace[prev_wp].y;
    double x_x = x - gpsTrace[prev_wp].x;
    double x_y = y - gpsTrace[prev_wp].y;

    // find the projection of x onto n
    double proj_norm = (x_x*n_x+x_y*n_y)/(n_x*n_x+n_y*n_y);
    double proj_x = proj_norm*n_x;
    double proj_y = proj_norm*n_y;  //proj_x、proj_y应该为垂足的坐标

    double frenet_d = sqrt((x_x - proj_x) * (x_x - proj_x) + (x_y - proj_y) * (x_y - proj_y));
    //经手动推算frenet_d = abs(n_x * x_y - n_y * x_x) / sqrt(n_x * n_x + n_y * n_y)。
    //即frenet_d,等于点(x,y)到 过prev_wp、next_wp两点的直线 的垂直距离。

    //see if d value is positive or negative by comparing it to a center point
    double center_x = 1000-gpsTrace[prev_wp].x;
    double center_y = 2000-gpsTrace[prev_wp].y;
    double centerToPos = distance(center_x,center_y,x_x,x_y);
    double centerToRef = distance(center_x,center_y,proj_x,proj_y);
    if(centerToPos <= centerToRef){
        frenet_d *= -1;
    }

    // calculate s value
    double frenet_s = 0;
    for(int i = 0; i < prev_wp; i++){
        frenet_s += distance(gpsTrace[i].x,gpsTrace[i].y,gpsTrace[i+1].x,gpsTrace[i+1].y);
    }
    if(prev_wp<=0){
        frenet_s -= distance(0,0,proj_x,proj_y);
    }else{
        frenet_s += distance(0,0,proj_x,proj_y);
    }

    double tmp_Angle = atan2(n_y,n_x);

    return {x:x,y:y,s:frenet_s,d:frenet_d,tangent_Ang:tmp_Angle};
}

 // frenet坐标转车体坐标。
 // Transform from Frenet s,d coordinates to Cartesian x,y
void iv::decition::FrenetPlanner::Frenet2XY(double *res_x, double *res_y, double s, double d, const vector<iv::decition::FrenetPoint>& frenetTrace){
    int prev_wp = 0;
    //退出循环时,prev_wp 最大是等于 frenetTrace.size()-2。
    while(s > frenetTrace[prev_wp+1].s && (prev_wp < (int)(frenetTrace.size()-2) )){
        prev_wp++;
    }
    int wp2 = prev_wp+1;
    double heading = atan2((frenetTrace[wp2].y-frenetTrace[prev_wp].y),(frenetTrace[wp2].x-frenetTrace[prev_wp].x));

    double seg_s = (s-frenetTrace[prev_wp].s);
    double seg_x = frenetTrace[prev_wp].x+seg_s*cos(heading);
    double seg_y = frenetTrace[prev_wp].y+seg_s*sin(heading);

    double perp_heading = heading-M_PI*0.5;
    *res_x = seg_x + d*cos(perp_heading);
    *res_y = seg_y + d*sin(perp_heading);
}

/* |==========================================================|
 * |         车辆坐标系与 frenet 坐标系互转的第二种方法。           |
 * |==========================================================| */
// 车体坐标转frenet坐标。frenet坐标原点是 gpsTrace 中序号为0的点。
iv::decition::FrenetPoint iv::decition::FrenetPlanner::getFrenetfromXY(double x, double y, const std::vector<iv::Point2D>& gpsTrace,const std::vector<iv::GPSData>& gpsMap,int pathpoint,GPS_INS nowGps){
    int next_wp=ClosestWaypoint( x,  y,  gpsTrace);
    int prev_wp = next_wp-1;  //prev_wp代表在next_wp的前一个点计算坐标,能够保证frenet_s都是依次相加的。避免在next_wp计算frenet_s的话,可能出现减的情况。
    //    if(next_wp == 0){
    //        prev_wp  = gpsTrace.size()-1;
    //    }

    GPS_INS gps = Coordinate_UnTransfer(x,y,nowGps);
    Point2D pt = Coordinate_Transfer(gps.gps_x,gps.gps_y, *gpsMap[(pathpoint+prev_wp)%gpsMap.size()]);

    // calculate s value
    double frenet_s = 0;
    for(int i = 0; i < prev_wp; i++){
        frenet_s += distance(gpsTrace[i].x,gpsTrace[i].y,gpsTrace[i+1].x,gpsTrace[i+1].y);
    }
    frenet_s += pt.y;

    //theta为prev_wp处车的航向角 与 nowGps处的车辆坐标系下x轴之间的夹角,逆时针为正。
    double theta = (nowGps.ins_heading_angle - gpsMap[(pathpoint+prev_wp)%gpsMap.size()]->ins_heading_angle+90);
    double tmp_Angle = theta * M_PI / 180;

    return {x:x,y:y,s:frenet_s,d:pt.x,tangent_Ang:tmp_Angle};
}

void iv::decition::FrenetPlanner::getXYfromFrenet(double *res_x, double *res_y, double s, double d, const vector<iv::decition::FrenetPoint>& frenetTrace,const std::vector<iv::GPSData>& gpsMap,int pathpoint,GPS_INS nowGps)
{
    int prev_wp = -1;

    while((prev_wp < (int)(frenetTrace.size()-1) ) && s > frenetTrace[prev_wp+1].s)
    {
        prev_wp++;
    }
    if(prev_wp < 0){
        prev_wp = 0;
    }
//    int wp2 =prev_wp+1;
    GPS_INS gps=  Coordinate_UnTransfer( d, s-frenetTrace[prev_wp].s , *gpsMap[(pathpoint+prev_wp)%gpsMap.size()]);
    Point2D pt =  Coordinate_Transfer( gps.gps_x, gps.gps_y, nowGps);

    *res_x = pt.x;
    *res_y = pt.y;
}


iv::decition::Quintic_polynomial::Quintic_polynomial(double xs, double vxs, double axs, double xe, double vxe, double axe, double T){
    //计算五次多项式系数
    this->xs = xs;
    this->vxs = vxs;
    this->axs = axs;
    this->xe = xe;
    this->vxe = vxe;
    this->axe = axe;

    this->a0 = xs;
    this->a1 = vxs;
    this->a2 = axs/ 2.0;

    MatrixXd A(3, 3);
    MatrixXd b(3, 1);
    MatrixXd x(3, 1);

    A << pow(T, 3),   pow(T, 4),   pow(T, 5),
         3*pow(T, 2), 4*pow(T, 3), 5*pow(T, 4),
         6*T,         12*T*T,      20*pow(T, 3);
    b << xe - a0 - a1*T - a2*T*T,
         vxe - a1 - 2*a2*T,
         axe - 2*a2;
    x=A.colPivHouseholderQr().solve(b);

    this->a3 = x(0,0);
    this->a4 = x(1,0);
    this->a5 = x(2,0);
}

iv::decition::Quintic_polynomial::~Quintic_polynomial(){
}

double iv::decition::Quintic_polynomial::calc_point(double t){
    double xt = this->a0 + this->a1 * t + this->a2 * t*t + this->a3 * t*t*t + this->a4 * t*t*t*t + this->a5 * t*t*t*t*t;
    return xt;
}

double iv::decition::Quintic_polynomial::calc_first_derivative(double t){
    double xt = this->a1 + 2*this->a2 * t + 3*this->a3 * t*t + 4*this->a4 * t*t*t + 5*this->a5 * t*t*t*t;
    return xt;
}

double iv::decition::Quintic_polynomial::calc_second_derivative(double t){
    double xt = 2*this->a2 + 6*this->a3 * t + 12*this->a4 * t*t + 20*this->a5 * t*t*t;
    return xt;
}

double iv::decition::Quintic_polynomial::calc_third_derivative(double t){
    double xt = 6*this->a3 + 24*this->a4 * t + 60*this->a5 * t*t;
    return xt;
}



iv::decition::Quartic_polynomial::Quartic_polynomial(double xs, double vxs, double axs, double vxe, double axe, double T){
    //计算四次多项式系数
    this->xs = xs;
    this->vxs = vxs;
    this->axs = axs;
    this->vxe = vxe;
    this->axe = axe;

    this->a0 = xs;
    this->a1 = vxs;
    this->a2 = axs / 2.0;

    MatrixXd A(2, 2);
    MatrixXd b(2, 1);
    MatrixXd x(2, 1);

    A << 3*pow(T, 2), 4*pow(T, 3),
         6*T,         12*T*T ;
    b << vxe - a1 - 2*a2*T,
         axe - 2*a2;
    x=A.colPivHouseholderQr().solve(b);

    this->a3 = x(0,0);
    this->a4 = x(1,0);
}

iv::decition::Quartic_polynomial::~Quartic_polynomial(){
}

double iv::decition::Quartic_polynomial::calc_point(double t){
    double xt = this->a0 + this->a1*t + this->a2*t*t + this->a3*t*t*t + this->a4*t*t*t*t;
    return xt;
}

double iv::decition::Quartic_polynomial::calc_first_derivative(double t){
    double xt = this->a1 + 2*this->a2*t + 3*this->a3*t*t + 4*this->a4*t*t*t;
    return xt;
}

double iv::decition::Quartic_polynomial::calc_second_derivative(double t){
    double xt = 2*this->a2 + 6*this->a3*t + 12*this->a4*t*t;
    return xt;
}

double iv::decition::Quartic_polynomial::calc_third_derivative(double t){
    double xt = 6*this->a3 + 24*this->a4*t;
    return xt;
}

bool iv::decition::FrenetPlanner::comp(const iv::decition::Frenet_path &a, const iv::decition::Frenet_path &b){
    return a.cf < b.cf;
}