道路匹配算法--C++

使用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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容