这两天要在一个三维场景中实现GPS定位的小模块。本来以为会很简单,但是写的过程中发现问题并没有想象中那么简单。最近老在学习,没有什么东西可在博客上写的,就凑合写点吧。
主要的目的为:将某一个移动GPS的运行轨迹在三维场景中实时展现,并以第一人称视角跟踪。
模块的核心部分大概是这样的:
1 捕获GPS传过来的数据,分解出位置坐标等信息,名称定为p1。
2 通过坐标在【系统】的三维场景中定位,得到场景中的屏幕坐标,利用该屏幕坐标求出该位置在场景中的地面高度
3 利用ORACLE数据库的空间分析能力缓冲查询p1点附近一定距离内的所有道路。并求出距离最近的那条道路,名称定 为line。
4 求出p1点在道路线line的垂足u1。
5 假设之前捕获的那个点为p0,在道路上的垂足为u0,那么用u0,u1两点可以求出道路线在该段的倾斜度。
6 将该倾斜度转化的与正北方向的夹角。
7 在p1点出创建一个标志对象,并让视角飞向该对象,视角位置为与道路线平行。
其他部分都比较简单,在第5部分卡了一个早上。测试不出问题。知道肯定哪个算法出错了。部分代码如下
1 private double GetYaw(double x0,double y0,double x1,double y1)
2 {
3 //以前一个垂足点作为基点构造新的坐标系统
4 double x=x1-x0;
5 double y=y1-y0;
6 double yaw=0;
7 if (x==0 && y==0)
8 yaw = preYaw;//preYaw为道路前一段的角度
9 else if (x == 0)
10 {
11 if (y > 0)
12 yaw = 90;//12点位置
13 else
14 yaw =270;//6点位置
15 }
16 else if (y == 0)
17 {
18 if (x > 0) //9点位置
19 yaw = 180;
20 else
21 yaw = 0; //3点位置
22 }
23 else
24 {
25 yaw = 180 * Math.Atan(y / x) / 3.14;
26 int qdt = GetQuadrant(x, y);
27 switch (qdt)
28 {
29 case 1://第一象限
30 yaw = yaw;
31 break;
32 case 2://第二象限
33 yaw += 180;
34 break;
35 case 3://第三象限
36 yaw += 180;
37 break;
38 case 4://第四象限
39 yaw += 360;
40 break;
41 default:
42 break;
43 }
44 }
45
46 return yaw;
47
48 }
49 //得到该点所在的象限
50 private int GetQuadrant(double x, double y)
51 {
52 int rst = 0;
53 if (x > 0 && y > 0)
54 rst = 1;
55 else if (x > 0 && y < 0)
56 rst = 4;
57 else if (x < 0 && y > 0)
58 rst = 2;
59 else
60 rst = 3;
61 return rst;
62 }
测试了1个消失也没有发现破绽,最后在上厕所的时候终于想到问题所在。首先因为数据局限在局部分析,我就采用了类似与平面坐标系统的做法。因为我们要求的只是个与指北方向的夹角,所以完全可以忽略那点误差。但是在坐标系统上我却想当然的忽略了 X,Y方向上的变性,由于在数值上X(经度)的值域为[0 -360],而Y[纬度]却是[90S 90N],地球的投影椭圆可以近似看成一个圆,X,Y上的长度一样,但是他们在数值上的值域缺不统一,所以这个坐标系统是非数值与角度变化率不是1:1
。讲到这里问题就非常清楚了,可能咋一看,是个很小的问题,但是习惯了平面坐标,偶然涉及到球面坐标就不小心弄错。最后,上面的代码只要加一句(x /= 2)纠正变形就可以了。