概述
在做模拟仿真的项目时,有时候需要加载地图上某一块的地貌和建筑,这时候我们只知道这些建筑在地图上的经纬度坐标,并不知道其在Unity中的世界坐标,那么如何才能将所有建筑按照真实地图显示出来就成了一个问题,本篇文章主要介绍的就是,如何通过经纬度,计算出其在Unity中的世界坐标。
注:因为Unity中的Vector3是float,所以本文中使用的是float类型的数据,精准度会有些许偏差,如果对精准度要求比较高,还请自己重写下Unity的Vector,将其重写为double类型的,在换算过程中我将使用double,只是最后返回值得时候会转成float。
思路分析
经纬度组合起来就是一个Vector2类型的数据。我们首先在Unity中创建两个点,两个点的位置就是一个正方形(长方形等)的对角线的位置即可,分别在地图上找到两个点的经纬度,也就是使用这两点,在地图上圈出来一个范围,将找到的这个两个点的经纬度,分别赋给在Unity中创建的两个点,这样我们在Unity中的范围位置,就和显示地图中的位置相对应了起来,在通过其坐标的X,Z轴的值和经纬度的差值,从而计算出坐标。具体示意图如下:
上图中,只要将图二中的AB点的经纬度,赋值给图一种AB点,即可通过坐标差,实时计算出由AB两点组成的正方形内的所有点的坐标
功能实现
上图中两个球就是确定位置的关键点。如果这两个点都没有确定好,那么一切都是白扯。 说通俗一点就是,已知A,B的位置和对应的数值,和 C 的位置,让你求 C 对应的值,是一个道理。 而我们在程序中们可以使用动态设置这两个定位点的位置,而不用一遍遍使用手动调节。
在程序中,我们还可以通过获取中心点的经纬度,通过向左右加减的方式,确定两角的坐标,这样做的好处就是不论是什么样的经纬度都可以计算出,并且不超出定位点单的范围。
首先进行程序的初始化,先确定两个定位点的坐标,以及两个坐标点在Unity中的经纬度的差
//本案例中是直接确定经纬度,不是通过中间点加减确定的
//点1
BottomRightSai = new Vector2(113.98071f, 22.52864f);
//点2
TopLeftSai = new Vector2(80.15071f, 40.56864f);
z_offset = BottomRightSai.y - TopLeftSai.y;//地图中的维度差
x_offset = BottomRightSai.x - TopLeftSai.x;//地图中的经度差
z_w_offset = BottomRightPoint.position.z - TopLeftPoint.position.z;//unity中的维度差
x_w_offset = BottomRightPoint.position.x - TopLeftPoint.position.x;//unity中的经度差
接下来是通过已知的经纬度,计算出该点在Unity中的坐标
注:此方法没法计算出在Unity中的高度,所有物体的Y轴是固定的,同定位点。如果想要使用高度,需要Unity读取灰度图才能够获取到高度
/// <summary>
/// 由经纬度得到位置点
/// </summary>
/// <param name="se"></param>
/// <returns></returns>
public Vector3 GetWorldPoint(Vector2 se)
{
double tempX = se.x - TopLeftSai.x;
double tempZ = se.y - BottomRightSai.y;
double _tempX = (tempX * x_w_offset / x_offset + TopLeftPoint.position.x);//计算X轴
double _tempZ = (tempZ * z_w_offset / z_offset + BottomRightPoint.position.z);//计算Z轴
//获取该点世界坐标
return new Vector3((float)_tempX, 0, (float)_tempZ);
}
由Unity坐标逆推经纬度同样的原理,还是上面提到的问题,经纬度一般都是double数据,此方法中使用的是float,精准度会有偏差,如果定位点范围较大可能不会有大影响,但是范围如果很小偏差可能会比较明显
/// <summary>
/// 由位置点得到经纬度
/// </summary>
/// <param name="curPoint"></param>
/// <returns></returns>
public Vector3 GetLatLon(Vector3 curPoint)
{
//坐标偏差
double _x_offset = (curPoint.x - BottomRightPoint.position.x) * x_offset / x_w_offset;
double _z_offset = (curPoint.z - TopLeftPoint.position.z) * z_offset / z_w_offset;
double resultX = _x_offset + BottomRightSai.x;
double resultZ = _z_offset + TopLeftSai.y;
return new Vector2((float)resultX, (float)resultZ);
}
到这里在Unity中经纬度转和世界坐标互转的功能就实现了,如果还有不明白的可以多研究下代码,其实原理还是很好理解的,案例源代码会在之后整理好之后放出。
注意
此案例功能比较单一,精准度由于float和double之间的转换,会有些许偏差,介意的同学请绕道。
写在最后
整体项目案例会在后期整理好之后分享给大家,如有错误之处还请多多指出。