道路匹配算法--C++

使用GPS信息將設(shè)備匹配到實(shí)際所處道路上蛛株。道路默認(rèn)為兩個(gè)點(diǎn)一條直線,具體的GPS信息通過高德地圖取得掂器,事先要將所需要匹配的城市道路都下載至本地摊欠。GPS的坐標(biāo)是標(biāo)準(zhǔn)的地球坐標(biāo)丢烘,高德和百度地圖都是對(duì)實(shí)際坐標(biāo)進(jìn)行了偏移處理,由于我們道路采集的坐標(biāo)是高德坐標(biāo)系些椒,所以在這個(gè)工程中需要將實(shí)際的GPS坐標(biāo)轉(zhuǎn)換成高德坐標(biāo)系播瞳。

目錄 (Table of Contents)

[TOC]

道路匹配算法流程圖

流程圖

道路匹配算法原理

總體方案:采用基于道路拓?fù)浣Y(jié)構(gòu)的權(quán)重匹配法,主要有三方面:距離D免糕,方向(航向)A赢乓,歷史方向H。最后計(jì)算權(quán)重總和石窑,為每條候選路段計(jì)算權(quán)重總和W牌芋,,則將具有最高權(quán)重和的候選路段作為匹配路段松逊,將該候選路段的虛擬匹配點(diǎn)作為匹配點(diǎn)躺屁。

1.距離匹配度

距離匹配

由于GPS系統(tǒng)內(nèi)在的誤差,在一般情況下接收到的數(shù)據(jù)定位點(diǎn)會(huì)偏離車輛實(shí)際行駛路段经宏。通過對(duì)定位點(diǎn)P作其在各個(gè)候選道路上的投影犀暑,投影點(diǎn)位為P0,所以GPS點(diǎn)到線段最短距離為點(diǎn)到投影距離PP0.
當(dāng)投影點(diǎn)在道路上的投影點(diǎn)不在線段內(nèi)烁兰,則點(diǎn)到線的最短距離母怜,為點(diǎn)到線段兩端的最短距離。

2.方向匹配度

方向匹配

在對(duì)候選路段進(jìn)行判斷時(shí)缚柏,可以通過確定誤差區(qū)域在第一時(shí)間排除不想管的候選路段。由于GPS系統(tǒng)接受到的定位點(diǎn)軌跡與電子地圖中的道路存在著方向上的偏差碟贾,因此需要對(duì)兩者進(jìn)行比較并將此作為一個(gè)重要的判斷因素币喧。
從GPS系統(tǒng)中接受到的數(shù)據(jù)信息可知車輛的運(yùn)行方向,然后分別計(jì)算車輛在每條候選路段上的方向匹配度袱耽。假設(shè)GPS系統(tǒng)顯示的定位點(diǎn)軌跡為路線L1杀餐, L2為實(shí)際道路,則計(jì)算兩條方向向量的角度差cos(α-β)作為方向匹配度的值

3.歷史方向匹配

在進(jìn)行道路判斷時(shí)朱巨,我們會(huì)將每個(gè)GPS點(diǎn)(也就是車輛軌跡)存儲(chǔ)在內(nèi)存空間史翘,加入現(xiàn)在GPS點(diǎn)為P0,前四個(gè)數(shù)據(jù)點(diǎn)分別為P-5,P-4,P-3,P-2,P-1 我們計(jì)算P0 P-,P0 P-4 P0P-3 P0P-2, P0P-1 五條線路與道路方向的角度差并求平均作為歷史方向匹配度的值。

4.權(quán)重分配

1.靜態(tài):將三個(gè)權(quán)重值平均分別為1/3,則每條道路的總得分為W=1/3*(D+A+H)琼讽,或者在之后的實(shí)際上路測(cè)試不斷調(diào)權(quán)重值得到對(duì)應(yīng)的經(jīng)驗(yàn)值
2.動(dòng)態(tài): 自動(dòng)分配權(quán)重必峰,先假設(shè)距離、方向钻蹬、歷史方向吼蚁、的權(quán)重值相同。在此從第一時(shí)候開始问欠,分別對(duì)每條候選道路的距離肝匆、方向、實(shí)時(shí)方向匹配度進(jìn)行排序顺献。然后在每時(shí)刻都將做出三個(gè)因素的最高匹配度與次高匹配度的差值旗国。在此,設(shè)定一個(gè)閾值h注整,若在一個(gè)時(shí)刻某個(gè)因素差值最大能曾,并且大于閾值h,則可以認(rèn)為在該時(shí)刻设捐,該因素的權(quán)重值占比重最大借浊,提高其權(quán)重值。

源代碼(C++)

GPS數(shù)據(jù)解析

//"$GPRMC,075507.00,A,3027.40466,N,11425.31127,E,0.792,,120517,,,A*7F\r\n" /*數(shù)據(jù)詳解:$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
 <1> UTC 時(shí)間萝招,hhmmss(時(shí)分秒)格式
 <2> 定位狀態(tài)蚂斤,A=有效定位,V=無效定位
 <3>緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)
 <4> 緯度半球N(北半球)或S(南半球)
 <5>經(jīng)度dddmm.mmmm(度分)格式(前面的0也將被傳輸)
  <6> 經(jīng)度半球E(東經(jīng))或W(西經(jīng))
  <7>地面速率(000.0~999.9節(jié)槐沼,前面的0也將被傳輸)
  <8>地面航向(000.0~359.9度曙蒸,以正北為參考基準(zhǔn),前面的0也將被傳輸)
   <9> UTC 日期岗钩,ddmmyy(日月年)格式
   <10>磁偏角(000.0~180.0度纽窟,前面的0也將被傳輸)
   <11> 磁偏角方向,E(東)或W(西)
   <12>模式指示(僅NMEA01833.00版本輸出兼吓,A=自主定位臂港,D=差分,E=估算视搏,N=數(shù)據(jù)無效)
解析內(nèi)容:
1.時(shí)間审孽,這個(gè)是格林威治時(shí)間,是世界時(shí)間(UTC)浑娜,我們需要把它轉(zhuǎn)換成北京時(shí)間(BTC)佑力,BTC和UTC差了8個(gè)小時(shí),要在這個(gè)時(shí)間基礎(chǔ)上加8個(gè)小時(shí)筋遭。
2. 定位狀態(tài)打颤,在接收到有效數(shù)據(jù)前暴拄,這個(gè)位是‘V’,后面的數(shù)據(jù)都為空编饺,接到有效數(shù)據(jù)后乖篷,這個(gè)位是‘A’,后面才開始有數(shù)據(jù)反肋。
 3. 緯度那伐,我們需要把它轉(zhuǎn)換成度分秒的格式,計(jì)算方法:如接收到的緯度是: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. 南北緯罕邀,這個(gè)位有兩種值‘N’(北緯)和‘S’(南緯)
5. 經(jīng)度的計(jì)算方法和緯度的計(jì)算方法一樣
6. 東西經(jīng),這個(gè)位有兩種值‘E’(東經(jīng))和‘W’(西經(jīng))
7. 速率养距,這個(gè)速率值是海里/時(shí)诉探,單位是節(jié),要把它轉(zhuǎn)換成千米/時(shí)棍厌,根據(jù):1海里=1.85公里肾胯,把得到的速率乘以1.85。
8. 航向耘纱,指的是偏離正北的角度
9. 日期敬肚,這個(gè)日期是準(zhǔn)確的,不需要轉(zhuǎn)換*/

GPS坐標(biāo)轉(zhuǎn)高德坐標(biāo)系(火星坐標(biāo)系)/百度坐標(biāo)系

/*******************************GPS坐標(biāo)系轉(zhuǎn)換***********************************/

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;
}

/**
 * 地球坐標(biāo)轉(zhuǎn)換為火星坐標(biāo)(WGS-84到GCJ-02)
 * World Geodetic System ==> Mars Geodetic System
 *
 * @param wgLat  地球坐標(biāo)
 * @param wgLon
 *
 * mglat,mglon 火星坐標(biāo)
 */
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;
}

/**
 * 火星坐標(biāo)轉(zhuǎn)換為百度坐標(biāo)(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;
}

/**
 * 百度轉(zhuǎn)火星
 * @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);
}

球面坐標(biāo)轉(zhuǎn)換成平面坐標(biāo)

struct geo{
    int projectType;   //分帶選擇:1--->3°帶投影    2--->6°帶投影
    int  parameter;    //參考橢球:1---->克拉索夫斯基橢球    2---->1975國際協(xié)議橢球    3---->WGS-84橢球
    double geo_B_d;    //經(jīng)度: geo_B_d--->度
    double geo_B_m;    //經(jīng)度: geo_B_m--->分
    double geo_B_s;    //經(jīng)度: 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;  //中央子午線經(jīng)度
    double plane_X;     //平面坐標(biāo)x
    double plane_Y;     //平面坐標(biāo)y
    double a;           //橢球參數(shù)a
    double b;           //橢球參數(shù)b
};

void gaussConvert(geo* m)     //坐標(biāo)轉(zhuǎn)換束析,將大地坐標(biāo)轉(zhuǎn)換成直角坐標(biāo)
{

        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;  //橢球參數(shù)

        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));

        //計(jì)算平面橫軸
        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);

        //計(jì)算平面縱軸
        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);

       //計(jì)算中央經(jīng)線經(jīng)度
      //  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=******;  //測(cè)試經(jīng)度點(diǎn)
typegeo.geo_L_d=******;   //測(cè)試緯度點(diǎn)
gaussConvert(&typegeo);
double x=typegeo.plane_X;
double y=typegeo.plane_Y;

點(diǎn)到線段的最短距離

double distancePointLine(double x,double y,double x1,double y1,double x2,double y2)  //p(x,y)實(shí)際點(diǎn) A(x1,y1) B(x2,y2) 點(diǎn)到線段的最短距離
{
    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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艳馒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子员寇,更是在濱河造成了極大的恐慌弄慰,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶锋,死亡現(xiàn)場(chǎng)離奇詭異陆爽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扳缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門慌闭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躯舔,你說我怎么就攤上這事驴剔。” “怎么了庸毫?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衫樊。 經(jīng)常有香客問我飒赃,道長利花,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任载佳,我火速辦了婚禮炒事,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔫慧。我一直安慰自己挠乳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布姑躲。 她就那樣靜靜地躺著睡扬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黍析。 梳的紋絲不亂的頭發(fā)上卖怜,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音阐枣,去河邊找鬼马靠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蔼两,可吹牛的內(nèi)容都是我干的甩鳄。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼额划,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼妙啃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锁孟,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤彬祖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后品抽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體储笑,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年圆恤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了突倍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盆昙,死狀恐怖羽历,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淡喜,我是刑警寧澤秕磷,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站炼团,受9級(jí)特大地震影響澎嚣,放射性物質(zhì)發(fā)生泄漏疏尿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一易桃、第九天 我趴在偏房一處隱蔽的房頂上張望褥琐。 院中可真熱鬧,春花似錦晤郑、人聲如沸敌呈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磕洪。三九已至,卻和暖如春匹舞,著一層夾襖步出監(jiān)牢的瞬間褐鸥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來泰國打工赐稽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叫榕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓姊舵,卻偏偏與公主長得像晰绎,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子括丁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容