同一坐标系中,由任意两点计算地图旋转角度(转载)

本文介绍了一种计算地图旋转角度的方法,适用于动态GPS导航等场景。通过分析前后两点坐标,利用反正切函数计算出北偏东的偏转角,进而实现地图的实时旋转。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

一、引言

在各种GIS/GPS应用中,地图旋转是不可或缺的一部分,尤其明显的是用在实时导航,对象跟踪等应用方面。用来计算地图旋转时偏转角的坐标点有动态和静态两种之分。动态在这里指的是在已知当前点的情况下,下一点的具体位置是不确定的;而静态指的是下一点的具体位置是确定的。动态的应用我们常见到的是GPS导航、游戏中的赛车(多赛道、可转弯等)以及调度等中的实时地图旋转,而静态更常见的是作为一种功能的演示,如模拟导航,模拟赛车等。地图旋转只有在同一坐标系中进行才有意义,地图旋转角度的计算才有依据,本文主要着重点在于如何由前后两点计算地图旋转角度,同时主要考虑动态的方式,静态方式的旋转地图原理是一样的,就不分开介绍了。

二、约定和术语

²      参考坐标系:本文所依据的坐标系为北京54下的依据高斯克吕格投影所建立的坐标系,即高斯平面坐标系,它的图像如图:


X
代表为正北方向,Y代表正东方向,为了使y值都为正,将纵坐标轴西移500km

²      正切函数是直角三角形中,对边与邻边的比值。放在直角坐标系中(如图)即 tanθ=y/x

其中tanθ的定义域为(-∏/2,+∏/2),值域为(-,+)

²         偏转角:约定偏转角为北偏东的角度,将地图按照偏转角进行旋转后将始终朝着运动方向行驶。在高斯平面坐标系中,正北即为X轴,正东即为Y轴,所以tanθ还是为y/x,只是角度的位置有了变化,如图所示。

²         反正切:函数y=tanx的反函数叫做反正切函数,记做:y=arctanx.
定义域:R;值域:(-π/2,π/2)
三、计算偏转角

假设存在一起始点pntBegin,并且存在一个原点为pntBegin的平面坐标系,同时约定要旋转的角度为rotateAngle,则下一点pntDest根据方位有几种情况,其示意图如下,我们可以分类进行讨论:


l       pntDest.x1>=pntBegin.x0,则该点在第一和第四象限,具体对应点为pntDest(1)pntDest(4),分别对应的北偏东角度为α(1)和α(4),根据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,则该点在第二和第三象限,具体对应点为pntDest(2)pntDest(3),分别对应的北偏东角度为α(2)和α(3),根据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;

四、在超图平台中实现
:开发语言为VC6,平台为eSuperMap;

代码如下:

 1
 2void CCarNaviView::RotateMap(CPoint pntBegin,CPoint pntNext)
 3{    
 4    //计算旋转角度
 5    double dAngle=CalculateRotateAngle(pntBegin,pntNext);
 6    //地图旋转
 7    m_MapWnd.GetDrawParam()->SetMapRotationAngle( dAngle );
 8    m_MapWnd.Refresh();
 9}

10
11/**//// \brief 由前后两点计算当前地图偏转角并进行地图旋转
12/// \param pntbegin 起始点
13/// \param pntbegin 下一点
14/// \return 地图要旋转的角度(北偏东)
15/// \remark 为适应习惯用法,点坐标的表示方法为cpoint(x,y),如pntbegin(x,y)代表的含义为:
16///          x->正东,即为高斯投影中的Y,y->正北,代表高斯投影中的x

17double 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}
### 不同坐标系间点的转换 #### 大地直角坐标系到空间直角坐标系的转换 对于给定的大地方位坐标 (L, B, H),可以计算其对应的空间直角坐标 (X, Y, Z)。该过程涉及到椭球体参数以及一系列几何关系的应用[^1]。 公式如下: \[ \begin{aligned} X &= (N + h)\cos(B)\cos(L) \\ Y &= (N + h)\cos(B)\sin(L) \\ Z &= ((1-e^2)N+h)\sin(B) \end{aligned} \] 其中 \( N=\frac{a}{\sqrt{1-e^{2}\sin ^{2}(B)}} \),\( a \) 和 \( e \) 分别代表参考椭球半径和偏心率;\( L \) 表示经度,\( B \) 是纬度而 \( H \) 则指代高程。 #### 使用矩阵表示法进行坐标变换 当描述两个笛卡尔坐标系统的相对位置时,可以通过定义旋转和平移来完成从一个系统到另一个系统的映射。假设存在一对基底向量 VX,VY,VZ 描述源坐标系的方向,并且 P 定义了目标坐标系相对于源坐标系的位置,则任意一点 p 在这两个坐标系内的坐标可通过下述方式关联起来[^2]: \[ T = R \cdot S + t \] 这里, - \(T\) 为目标坐标; - \(S\) 为原始坐标; - \(R=[VX| VY | VZ]\) 构成旋转变换矩阵; - \(t=P\) 是平移矢量。 #### 平面内两坐标系间的线性变换 考虑维情况,在同一水平面上有两个不同的正交坐标体系 A 和 B ,如果知道它们之间的角度差 θ 及原点偏差 (\(x_0 , y_0\)) ,则可利用下面给出的关系式来进行坐标互转[^3]: \[ \begin{cases} x = x' \times \cos(\theta)-y'\times\sin(\theta)+x_{0}\\ y= x'\times\sin(\theta)+y'\times\cos(\theta)+y_{0} \end{cases} \] 以上方法适用于处理简单的平行移动或绕某固定轴的小范围转动场景。 #### 特殊地理信息系统中的坐标转换实例——GCJ-02 至 BD09 的转换 针对特定应用领域如地图服务提供商所采用的不同标准,比如 GCJ-02(火星坐标系)至 BD09(百度坐标系),有专门设计好的函数用于执行这种类型的转换操作[^4]。 ```java public static double[] gcj2BD09(double glat, double glon){ double x = glon; double y = glat; double[] latlon = new double[2]; final double X_PI = Math.PI / 180.0; double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * X_PI); double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * X_PI); latlon[0] = z * Math.sin(theta) + 0.006; latlon[1] = z * Math.cos(theta) + 0.0065; return latlon; } ``` 这段代码实现了由 GCJ-02 向 BD09 转化的逻辑,通过引入微小扰动项调整经纬度数以匹配目的地坐标系的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值