一、引言
在各種GIS/GPS應(yīng) 用中,地圖旋轉(zhuǎn)是不可或缺的一部分,尤其明顯的是用在實時導(dǎo)航,對象跟蹤等應(yīng)用方面。用來計算地圖旋轉(zhuǎn)時偏轉(zhuǎn)角的坐標點有動態(tài)和靜態(tài)兩種之分。動態(tài)在這里 指的是在已知當前點的情況下,下一點的具體位置是不確定的;而靜態(tài)指的是下一點的具體位置是確定的。動態(tài)的應(yīng)用我們常見到的是GPS導(dǎo)航、游戲中的賽車(多賽道、可轉(zhuǎn)彎等)以 及調(diào)度等中的實時地圖旋轉(zhuǎn),而靜態(tài)更常見的是作為一種功能的演示,如模擬導(dǎo)航,模擬賽車等。地圖旋轉(zhuǎn)只有在同一坐標系中進行才有意義,地圖旋轉(zhuǎn)角度的計算 才有依據(jù),本文主要著重點在于如何由前后兩點計算地圖旋轉(zhuǎn)角度,同時主要考慮動態(tài)的方式,靜態(tài)方式的旋轉(zhuǎn)地圖原理是一樣的,就不分開介紹了。
二、約定和術(shù)語
² 參考坐標系:本文所依據(jù)的坐標系為北京54下的依據(jù)高斯克呂格投影所建立的坐標系,即高斯平面坐標系,它的圖像如圖:

X代表為正北方向,Y代表正東方向,為了使y值都為正,將縱坐標軸西移500km。
² 正切函數(shù)是直角三角形中,對邊與鄰邊的比值。放在直角坐標系中(如圖)即 tanθ=y/x
其中tanθ的定義域為(-∏/2,+∏/2),值域為(-∞,+∞)

² 偏轉(zhuǎn)角:約定偏轉(zhuǎn)角為北偏東的角度,將地圖按照偏轉(zhuǎn)角進行旋轉(zhuǎn)后將始終朝著運動方向行駛。在高斯平面坐標系中,正北即為X軸,正東即為Y軸,所以tanθ還是為y/x,只是角度的位置有了變化,如圖所示。

² 反正切:函數(shù)y=tanx的反函數(shù)叫做反正切函數(shù),記做:y=arctanx.
定義域:R;值域:(-π/2,π/2)
三、計算偏轉(zhuǎn)角
假設(shè)存在一起始點pntBegin,并且存在一個原點為pntBegin的平面坐標系,同時約定要旋轉(zhuǎn)的角度為rotateAngle,則下一點pntDest根據(jù)方位有幾種情況,其示意圖如下,我們可以分類進行討論:

l 若pntDest.x1>=pntBegin.x0,則該點在第一和第四象限,具體對應(yīng)點為pntDest(1)和pntDest(4),分別對應(yīng)的北偏東角度為α(1)和α(4),根據(jù)Y值的不同,我們又可以分兩種情況,
n 若pntDest.y>=pntBegin.y://在第一象限
rotateAngle=arctan2(fabs(p0.x-p1.x),fabs(p0.y-p1.y));
n 若pntDest.y<pntBegin.y://在第四象限
rotateAngle=arctan2(fabs(p0.x-p1.x),fabs(p0.y-p1.y));
rotateAngle=∏-rotateAngle;
l 若pntDest.x1<pntBegin.x0,則該點在第二和第三象限,具體對應(yīng)點為pntDest(2)和pntDest(3),分別對應(yīng)的北偏東角度為α(2)和α(3),根據(jù)Y值的不同,分兩種情況進行討論,
n 若pntDest.y>=pntBegin.y://在第二象限
rotateAngle=arctan2(fabs(p0.x-p1.x),fabs(p0.y-p1.y));
rotateAngle= 2*∏-rotateAngle;
n 若pntDest.y<pntBegin.y://在第三象限
rotateAngle=arctan2(fabs(p0.x-p1.x),fabs(p0.y-p1.y));
rotateAngle=∏+rotateAngle;
四、在超圖平臺中實現(xiàn)
注:開發(fā)語言為VC6,平臺為eSuperMap;
代碼如下:
1
2
void CCarNaviView::RotateMap(CPoint pntBegin,CPoint pntNext)
3

{
4
//計算旋轉(zhuǎn)角度
5
double dAngle=CalculateRotateAngle(pntBegin,pntNext);
6
//地圖旋轉(zhuǎn)
7
m_MapWnd.GetDrawParam()->SetMapRotationAngle( dAngle );
8
m_MapWnd.Refresh();
9
}
10
11
/**//// \brief 由前后兩點計算當前地圖偏轉(zhuǎn)角并進行地圖旋轉(zhuǎn)
12
/// \param pntbegin 起始點
13
/// \param pntbegin 下一點
14
/// \return 地圖要旋轉(zhuǎn)的角度(北偏東)
15
/// \remark 為適應(yīng)習(xí)慣用法,點坐標的表示方法為cpoint(x,y),如pntbegin(x,y)代表的含義為:
16
/// x->正東,即為高斯投影中的Y,y->正北,代表高斯投影中的x 17
double CCarNaviView::CalculateRotateAngle(CPoint pntBegin,CPoint pntNext)
18

{
19
CPoint pntFirst(pntBegin);
20
CPoint pntSecond(pntNext);
21
22
double dRotateAngle = atan2(fabs(pntBegin.x-pntNext.x),fabs(pntBegin.y-pntNext.y));
23
24
//如果下一點的橫坐標大于前一點(在第一和第四象限)
25
if (pntNext.x>=pntFirst.x)
26
{
27
//在第一象限(0<=dRotateAngle<=90)
28
if (pntNext.y>=pntFirst.y)
29
{
30
//不做任何處理
31
dRotateAngle=dRotateAngle;
32
}
33
else
34
{
35
dRotateAngle=PI-dRotateAngle;
36
}
37
}
38
else//(在第二和第三象限)
39
{
40
//第二象限
41
if (pntNext.y>=pntFirst.y)
42
{
43
dRotateAngle=2*PI-dRotateAngle;
44
}
45
else//第三象限
46
{
47
dRotateAngle=PI+dRotateAngle;
48
}
49
}
50
return dRotateAngle;
51
}