在开发与经纬度有关的项目时,通常需要将经纬度座标与3D引擎中的座标系进行互相换算。本次创新以Unity3D为例,使用一系列算法将经纬度座标与3D座标系进行换算。
1.座标系分析(以Unity3D左手座标系为例)
经纬度座标是描述球面上某个点的位置,若已知球体半径(R)和球体中心点的3D座标(O)便可通过一些列计算的到3D座标系中的座标点(P)。
通过经度可以计算出 ∠AOB的度数
通过纬度可以计算出 ∠BOP的度数
经度转3D座标公式:
X=R*Cos(∠BOP)*Cos(∠AOB)
Y=R*Cos(∠BOP)*Sin(∠AOB)
Z=R*(∠BOP)
经度转3D座标公式:
∠BOP=Asin(Z/R)
∠AOB=Asin(Y/X)
2.具体实现:
座标转换功能
using UnityEngine;
using System.Collections;
public class SaiGetLatLog : MonoBehaviour {
public Transform firstPoint; //Unity中左上点
public Transform secondPoint;//Unity中右下点
public SaiEarth firstSai;//地图中对应的左上经纬度点
public SaiEarth secondSai;//地图中对应的右下经纬度点
private float z_offset,x_offset,z_w_offset,x_w_offset;
private RaycastHit rayHit;
// Use this for initialization
void Start () {
InitBasicNum ();//初始化参数
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0) && Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out rayHit, Mathf.Infinity)) {
print ( getWorldPoint(firstSai).x+","+ getWorldPoint(firstSai).z);
}
}
void InitBasicNum()
{
firstSai = new SaiEarth (new Vector3 (116f, 23f, 9.27f), new Vector3 (39f, 55f, 15.74f));
secondSai = new SaiEarth (new Vector3(116f,23f,44.39f),new Vector3(39f,54f,44.27f));
z_offset = Mathf.Abs ((firstSai.latitude.x+firstSai.latitude.y/60+firstSai.latitude.z/3600) - (secondSai.latitude.x+secondSai.latitude.y/60+secondSai.latitude.z/3600));//地图中的维度差
x_offset = Mathf.Abs ((firstSai.longitude.x+firstSai.longitude.y/60+firstSai.longitude.z/3600)-(secondSai.longitude.x+secondSai.longitude.y/60+secondSai.longitude.z/3600));//地图中的经度差
z_w_offset = Mathf.Abs (firstPoint.localPosition.z - secondPoint.localPosition.z);//unity中的维度差
x_w_offset = Mathf.Abs (firstPoint.localPosition.x - secondPoint.localPosition.x);//unity中的经度差
}
Vector3 getWorldPoint(SaiEarth se)//由经纬度得到位置点
{
float tempX = (float)(se.longitude.x + se.longitude.y / 60 + se.longitude.z / 3600 - (secondSai.longitude.x + secondSai.longitude.y / 60 + secondSai.longitude.z / 3600));
float tempZ = (float)(se.latitude.x + se.latitude.y / 60 + se.latitude.z / 3600 - (secondSai.latitude.x + secondSai.latitude.y / 60 + secondSai.latitude.z / 3600));
float _tempX = (float)(tempX * x_w_offset / x_offset + secondPoint.localPosition.x);
float _tempZ = (float)(tempZ * z_w_offset / z_offset + secondPoint.localPosition.z);
return new Vector3((float)_tempX,0f,(float)_tempZ);
}
SaiEarth getLatLon(Vector3 curPoint)//由位置点得到经纬度
{
SaiEarth tempEarth = new SaiEarth();
float _z_offset = Mathf.Abs (curPoint.z - secondPoint.localPosition.z) * z_offset / z_w_offset;
float _x_offset = Mathf.Abs (curPoint.x - secondPoint.localPosition.x) * x_offset / x_w_offset;
float resultX = _x_offset + (secondSai.longitude.x + secondSai.longitude.y/60 + secondSai.longitude.z/3600);
float resultZ = _z_offset + (secondSai.latitude.x + secondSai.latitude.y/60 + secondSai.latitude.z/3600);
tempEarth.longitude = new Vector3 ((int)resultX, (int)((resultX - (int)resultX)*60),((resultX - (int)resultX)*60 - (int)((resultX - (int)resultX)*60))*60);
tempEarth.latitude = new Vector3 ((int)resultZ, (int)((resultZ - (int)resultZ)*60),((resultZ - (int)resultZ)*60 - (int)((resultZ - (int)resultZ)*60))*60);
return tempEarth;
}
}
using UnityEngine;
using System.Collections;
public class SaiEarth {
public Vector3 longitude;
public Vector3 latitude;
public SaiEarth()
{
}
public SaiEarth(Vector3 longitude,Vector3 latitude)
{
this.latitude = latitude;
this.longitude = longitude;
}
public string toString()
{
return "Lat:"+this.latitude + ",Long:" + this.longitude;
}
}