美文网首页
道路匹配算法--C++

道路匹配算法--C++

作者: AngryCJ | 来源:发表于2018-02-09 11:36 被阅读0次

使用GPS信息将设备匹配到实际所处道路上。道路默认为两个点一条直线,具体的GPS信息通过高德地图取得,事先要将所需要匹配的城市道路都下载至本地。GPS的坐标是标准的地球坐标,高德和百度地图都是对实际坐标进行了偏移处理,由于我们道路采集的坐标是高德坐标系,所以在这个工程中需要将实际的GPS坐标转换成高德坐标系。

目录 (Table of Contents)

[TOC]

道路匹配算法流程图

流程图

道路匹配算法原理

总体方案:采用基于道路拓扑结构的权重匹配法,主要有三方面:距离D,方向(航向)A,历史方向H。最后计算权重总和,为每条候选路段计算权重总和W,,则将具有最高权重和的候选路段作为匹配路段,将该候选路段的虚拟匹配点作为匹配点。

1.距离匹配度

距离匹配

由于GPS系统内在的误差,在一般情况下接收到的数据定位点会偏离车辆实际行驶路段。通过对定位点P作其在各个候选道路上的投影,投影点位为P0,所以GPS点到线段最短距离为点到投影距离PP0.
当投影点在道路上的投影点不在线段内,则点到线的最短距离,为点到线段两端的最短距离。

2.方向匹配度

方向匹配

在对候选路段进行判断时,可以通过确定误差区域在第一时间排除不想管的候选路段。由于GPS系统接受到的定位点轨迹与电子地图中的道路存在着方向上的偏差,因此需要对两者进行比较并将此作为一个重要的判断因素。
从GPS系统中接受到的数据信息可知车辆的运行方向,然后分别计算车辆在每条候选路段上的方向匹配度。假设GPS系统显示的定位点轨迹为路线L1, L2为实际道路,则计算两条方向向量的角度差cos(α-β)作为方向匹配度的值

3.历史方向匹配

在进行道路判断时,我们会将每个GPS点(也就是车辆轨迹)存储在内存空间,加入现在GPS点为P0,前四个数据点分别为P-5,P-4,P-3,P-2,P-1 我们计算P0 P-,P0 P-4 P0P-3 P0P-2, P0P-1 五条线路与道路方向的角度差并求平均作为历史方向匹配度的值。

4.权重分配

1.静态:将三个权重值平均分别为1/3,则每条道路的总得分为W=1/3*(D+A+H),或者在之后的实际上路测试不断调权重值得到对应的经验值
2.动态: 自动分配权重,先假设距离、方向、历史方向、的权重值相同。在此从第一时候开始,分别对每条候选道路的距离、方向、实时方向匹配度进行排序。然后在每时刻都将做出三个因素的最高匹配度与次高匹配度的差值。在此,设定一个阈值h,若在一个时刻某个因素差值最大,并且大于阈值h,则可以认为在该时刻,该因素的权重值占比重最大,提高其权重值。

源代码(C++)

GPS数据解析

//"$GPRMC,075507.00,A,3027.40466,N,11425.31127,E,0.792,,120517,,,A*7F\r\n" /*数据详解:$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
 <1> UTC 时间,hhmmss(时分秒)格式
 <2> 定位状态,A=有效定位,V=无效定位
 <3>纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
 <4> 纬度半球N(北半球)或S(南半球)
 <5>经度dddmm.mmmm(度分)格式(前面的0也将被传输)
  <6> 经度半球E(东经)或W(西经)
  <7>地面速率(000.0~999.9节,前面的0也将被传输)
  <8>地面航向(000.0~359.9度,以正北为参考基准,前面的0也将被传输)
   <9> UTC 日期,ddmmyy(日月年)格式
   <10>磁偏角(000.0~180.0度,前面的0也将被传输)
   <11> 磁偏角方向,E(东)或W(西)
   <12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
解析内容:
1.时间,这个是格林威治时间,是世界时间(UTC),我们需要把它转换成北京时间(BTC),BTC和UTC差了8个小时,要在这个时间基础上加8个小时。
2. 定位状态,在接收到有效数据前,这个位是‘V’,后面的数据都为空,接到有效数据后,这个位是‘A’,后面才开始有数据。
 3. 纬度,我们需要把它转换成度分秒的格式,计算方法:如接收到的纬度是:4546.40891      4546.40891/100=45.4640891可以直接读出45度, 4546.40891–45*100=46.40891, 可以直接读出46分46.40891–46 =0.40891*60=24.5346读出24秒, 所以纬度是:45度46分24秒。
4. 南北纬,这个位有两种值‘N’(北纬)和‘S’(南纬)
5. 经度的计算方法和纬度的计算方法一样
6. 东西经,这个位有两种值‘E’(东经)和‘W’(西经)
7. 速率,这个速率值是海里/时,单位是节,要把它转换成千米/时,根据:1海里=1.85公里,把得到的速率乘以1.85。
8. 航向,指的是偏离正北的角度
9. 日期,这个日期是准确的,不需要转换*/

GPS坐标转高德坐标系(火星坐标系)/百度坐标系

/*******************************GPS坐标系转换***********************************/

const double pi = 3.14159265358979324;
const double a = 6378245.0;
const double ee = 0.00669342162296594323;
const  double x_pi = 3.14159265358979324 * 3000.0 / 180.0;

bool outOfChina(double lat, double lon)
{
    if (lon < 72.004 || lon > 137.8347)
    {
        return true;
    }

    if (lat < 0.8293 || lat > 55.8271)
    {
        return true;
    }

    return false;
}

double transformLat(double x, double y)
{
    double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(abs(x));
    ret += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 * sin(y * pi) + 40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0;
    ret += (160.0 * sin(y / 12.0 * pi) + 320 * sin(y * pi / 30.0)) * 2.0 / 3.0;

    return ret;
}

double transformLon(double x, double y)
{
    double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(abs(x));
    ret += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 * sin(x * pi) + 40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0;
    ret += (150.0 * sin(x / 12.0 * pi) + 300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0;

    return ret;
}

/**
 * 地球坐标转换为火星坐标(WGS-84到GCJ-02)
 * World Geodetic System ==> Mars Geodetic System
 *
 * @param wgLat  地球坐标
 * @param wgLon
 *
 * mglat,mglon 火星坐标
 */
void Transform2Mars(double wgLat, double wgLon,double &mgLat,double &mgLon)
{
    if (outOfChina(wgLat, wgLon))
    {
        qDebug() << "outOfChina";
        mgLat = wgLat;
        mgLon = wgLon;
        return;
    }

    double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
    double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
    double radLat = wgLat / 180.0 * pi;
    double magic = sin(radLat);

    magic = 1 - ee * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
    dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi);
    mgLat = wgLat + dLat;
    mgLon = wgLon + dLon;
    qDebug() << "mgLat111=" << mgLat << "mgLon111=" << mgLon;
}

/**
 * 火星坐标转换为百度坐标(GCJ-02到BD-09)
 * @param gg_lat
 * @param gg_lon
 */
void BD_encrypt(double gg_lat, double gg_lon,double &bd_lat,double &bd_lon)
{
    double x = gg_lon, y = gg_lat;
    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
    double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);

    bd_lon = z * cos(theta) + 0.0065;
    bd_lat = z * sin(theta) + 0.006;
}

/**
 * 百度转火星
 * @param bd_lat
 * @param bd_lon
 */
void BD_decrypt(double bd_lat, double bd_lon,double &gg_lat,double &gg_lon)
{
    double x = bd_lon - 0.0065, y = bd_lat - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
    double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);

    gg_lon = z * cos(theta);
    gg_lat = z * sin(theta);
}

球面坐标转换成平面坐标

struct geo{
    int projectType;   //分带选择:1--->3°带投影    2--->6°带投影
    int  parameter;    //参考椭球:1---->克拉索夫斯基椭球    2---->1975国际协议椭球    3---->WGS-84椭球
    double geo_B_d;    //经度: geo_B_d--->度
    double geo_B_m;    //经度: geo_B_m--->分
    double geo_B_s;    //经度: geo_B_s--->秒
    double geo_L_d;    //维度: geo_L_d--->度
    double geo_L_m;    //纬度: geo_L_m--->分
    double geo_L_s;    //维度: geo_L_s--->秒
    double centerLong;  //中央子午线经度
    double plane_X;     //平面坐标x
    double plane_Y;     //平面坐标y
    double a;           //椭球参数a
    double b;           //椭球参数b
};

void gaussConvert(geo* m)     //坐标转换,将大地坐标转换成直角坐标
{

        double N;
        double t;
        double Eta;
        double X;
        double A0,A2,A4,A6,A8;
        double RadB;

        double Rou;
        Rou=180*3600/PI;

        double a,b,e1,e2;  //椭球参数

        LawJudge::getParameter(m);
        a=m->a;
        b=m->b;
        e1=sqrt(a*a-b*b)/a;
        e2=sqrt(a*a-b*b)/b;

        double l;
        double L0;
        LawJudge::getProjectType(m);
        L0=m->centerLong;
        double L;
        L=m->geo_L_d+m->geo_L_m/60+m->geo_L_s/3600;
        l=(L-L0)*3600;

        RadB=(m->geo_B_d+m->geo_B_m/60+m->geo_B_s/3600)*PI/180;

        N=a/sqrt(1-e1*e1*sin(RadB)*sin(RadB));
        t=tan(RadB);
        Eta=e2*cos(RadB);

        A0=1+3.0/4*e1*e1+45.0/64*pow(e1,4)+350.0/512*pow(e1,6)+11025.0/16384*pow(e1,8);
        A2=-1.0/2*(3.0/4*e1*e1+60.0/64*pow(e1,4)+525.0/512*pow(e1,6)+17640.0/16384*pow(e1,8));
        A4=1.0/4*(15.0/64*pow(e1,4)+210.0/512*pow(e1,6)+8820.0/16384*pow(e1,8));
        A6=-1.0/6*(35.0/512*pow(e1,6)+2520.0/16384*pow(e1,8));
        A8=1.0/8*(315.0/16384*pow(e1,8));
        X=a*(1-e1*e1)*(A0*RadB+A2*sin(2*RadB)+A4*sin(4*RadB)+A6*sin(6*RadB)+A8*sin(8*RadB));

        //计算平面横轴
        m->plane_X=X+N/(2*Rou*Rou)*sin(RadB)*cos(RadB)*l*l+
            N/(24*pow(Rou,4))*sin(RadB)*pow(cos(RadB),3)*(5-t*t+9*Eta*Eta+4*pow(Eta,4))*pow(l,4)+
            N/(720*pow(Rou,6))*sin(RadB)*pow(cos(RadB),5)*(61-58*t*t+pow(t,4))*pow(l,6);

        //计算平面纵轴
        m->plane_Y=N/Rou*cos(RadB)*l+
            N/(6*pow(Rou,3))*pow(cos(RadB),3)*(1-t*t+Eta*Eta)*pow(l,3)+
            N/(120*pow(Rou,5))*pow(cos(RadB),5)*(5-18*t*t+pow(t,4)+14*Eta*Eta-58*Eta*Eta*t*t)*pow(l,5);

       //计算中央经线经度
      //  centerLong=L0;

}


geo typegeo={0,0,0,0,0,0,0,0,0,0,0,0,0};
typegeo.parameter=1;
typegeo.projectType=1;
typegeo.geo_B_d=******;  //测试经度点
typegeo.geo_L_d=******;   //测试纬度点
gaussConvert(&typegeo);
double x=typegeo.plane_X;
double y=typegeo.plane_Y;

点到线段的最短距离

double distancePointLine(double x,double y,double x1,double y1,double x2,double y2)  //p(x,y)实际点 A(x1,y1) B(x2,y2) 点到线段的最短距离
{
    double R=(x2-x1)*(x-x1)+(y2-y1)*(y-y1);
    double D=(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
    if(R<=0)                                            //最短距离等于AP
    {
        return sqrt(pow((x1-x),2)+pow((y1-y),2));
    }
    else if(R>=D)                                       //最短距离等于BP
    {
        return sqrt(pow((x2-x),2)+pow((y2-y),2));
    }
    else                                                //最短距离等于垂线
    {
        double r=R/D;
        double px=x1+(x2-x1)*r;
        double py=y1+(y2-y1)*r;
        return sqrt(pow((px-x),2)+pow((py-y),2));
    }

}

两条线段的夹角

double LawJudge::straightAngle(double x,double y,double x1,double y1)   //求两条方向向量A=(x,y)和 B=(x1,y1)的夹角
{
    double A=x*x1+y*y1;
    double B;
    if(A==0)
    {
        B=1;
    }
    else
    {
        B=(sqrt(pow(x,2)+pow(y,2)))*(sqrt(pow(x1,2)+pow(y1,2))) ;
    }
    double angel=abs(A/B);
    double hudu=acos(angel);         //弧度
    double jiaodu=(180*hudu)/PI;     //角度
    return jiaodu;
}

相关文章

  • 道路匹配算法--C++

    使用GPS信息将设备匹配到实际所处道路上。道路默认为两个点一条直线,具体的GPS信息通过高德地图取得,事先要将所需...

  • KMP 算法

    KMP 算法 1. 暴力匹配算法 在分析KMP算法前, 先看看暴力匹配算法是如何工作的.暴力匹配算法的基本思想是:...

  • sklearn学习笔记——正交匹配追踪算法OMP

    正交匹配追踪算法OMP(Orthogonal Matching Pursuit) 1、MP算法(匹配追踪算法) 作...

  • 字符串匹配算法

    以下为学习 《数据结构与算法之美 -- 字符串匹配》 的记录。 BF算法 即暴力匹配算法,循环遍历匹配。 RK算法...

  • 字符串匹配

    indexOf 底层就是使用字符串匹配算法 字符串匹配算法很多 BF( Brute Force)算法 暴力匹配算...

  • 串的模式匹配算法

    KMP算法 算法匹配

  • 自然语言处理中的分词算法实现

    最近实现的3种中文分词算法 基于最大匹配(前向匹配、后向匹配、双向匹配) HMM n-gram 基于最大匹配算法(...

  • 中文分词的方法

    1、基于字符串匹配的方法 1.1 正向最大匹配分词算法1.2 逆向最大匹配分词算法1.3 双向最大匹配分词算法1....

  • 字符串匹配算法--BF算法与RK算法

    BF算法 BF算法中的BF是brute force的缩写,中文叫做暴力匹配算法,也加朴素匹配算法。算法特点:“暴力...

  • 14.字符串匹配算法

    1.BF算法 1.1 定义 BF(Brute Force)算法,中文叫作暴力匹配算法,也叫朴素匹配算法。思想:在主...

网友评论

      本文标题:道路匹配算法--C++

      本文链接:https://www.haomeiwen.com/subject/edjqkxtx.html