Unity坐标转换经纬度方法(线性变换)
解决问题
针对缩放,旋转,翻转的两套坐标系转换。
线性变换原理
所有的线性坐标转换都是其基坐标的缩放和旋转。
变换公式
∣ a b c d ∣ ∣ O i O j ∣ = ∣ T i T j ∣ \begin{vmatrix} a & b \\ c & d\end{vmatrix}\begin{vmatrix} O_i \\ O_j\end{vmatrix}=\begin{vmatrix} T_i\\T_j\end{vmatrix} acbd OiOj = TiTj
T
i
=
a
∗
O
i
+
b
∗
O
j
T_i=a* O_i+b* O_j
Ti=a∗Oi+b∗Oj
T
j
=
c
∗
O
i
+
d
∗
O
j
T_j= c* O_i+d* O_j
Tj=c∗Oi+d∗Oj
Oi和Oj是变换前的坐标系的基坐标
Ti和Tj是变换后的坐标系的基坐标
所以,只有求出变换的二项式
∣
a
b
c
d
∣
\begin{vmatrix} a & b \\ c & d \end{vmatrix}
acbd
就可以完成坐标转换。
行列式创建
求取二项式,至少要知道两组变换前后的向量,且不能为平行向量,求解方法如下
/// <summary>
/// 求变换行列式
/// </summary>
/// <param name="T1">转换后向量1</param>
/// <param name="T2">转换后向量2</param>
/// <param name="M1">转换前向量1</param>
/// <param name="M2">转换前向量2</param>
/// <returns></returns>
DoubleVector4 GetChangeMatrix(DoubleVector2 T1, DoubleVector2 T2, DoubleVector2 O1, DoubleVector2 O2)
{
DoubleVector4 my_Matrix = new DoubleVector4();
DoubleVector2 AB = GetVec(T1.x, T2.x, O1, O2);
DoubleVector2 CD = GetVec(T1.y, T2.y, O1, O2);
my_Matrix.x = AB.x;
my_Matrix.y = AB.y;
my_Matrix.z = CD.x;
my_Matrix.w = CD.y;
return my_Matrix;
}
#region 求变换行列式
/// <summary>
/// 求二维行列式的一行的两个值,用两个点反求
/// </summary>
/// <param name="T1">转换后向量1的x或者y</param>
/// <param name="T2">转换后向量2的x或者y</param>
/// <param name="M1">转换前向量1</param>
/// <param name="M2">转换前向量2</param>
/// <returns></returns>
DoubleVector2 GetVec(double T1, double T2, DoubleVector2 O1, DoubleVector2 O2)
{
DoubleVector2 vector = new DoubleVector2();
double BD = ((O2.x * T1) - (T2 * O1.x)) / ((O1.y * O2.x) - (O2.y * O1.x));
double AC = (T1 - (BD * O1.y)) / O1.x;
vector.x = AC;
vector.y = BD;
return vector;
}
这里是把ab和cd分开求解,既二个二元一次方程组
{
T
1
i
=
a
∗
O
1
i
+
b
∗
O
1
j
T
2
i
=
a
∗
O
2
i
+
b
∗
O
2
j
\begin{cases} T_1i=a* O_1i+b* O_1j\\ T_2i=a* O_2i+b* O_2j \end{cases}
{T1i=a∗O1i+b∗O1jT2i=a∗O2i+b∗O2j
{
T
1
j
=
c
∗
O
1
i
+
d
∗
O
1
j
T
2
j
=
c
∗
O
2
i
+
d
∗
O
2
j
\begin{cases} T_1j=c* O_1i+d* O_1j\\ T_2j=c* O_2i+d* O_2j \end{cases}
{T1j=c∗O1i+d∗O1jT2j=c∗O2i+d∗O2j
行列式应用
#region 变换行列式应用
/// <summary>
/// 得到变换后的坐标
/// </summary>
/// <param name="Vector">变换前向量</param>
/// <param name="ChangeMatrix">变换行列式</param>
/// <param name="VecZero">变换后原点坐标</param>
/// <param name="VecZero">变换前原点坐标</param>
/// <returns></returns>
public DoubleVector2 GetChangeVector(DoubleVector2 Vector, DoubleVector4 ChangeMatrix, DoubleVector2 TZero, DoubleVector2 OZero)
{
DoubleVector2 OVector2 = Vector - OZero;
double x = (OVector2.x * ChangeMatrix.x) + (OVector2.y * ChangeMatrix.y)+ TZero.x;
double y = (OVector2.x * ChangeMatrix.z) + (OVector2.y * ChangeMatrix.w) + TZero.y;
DoubleVector2 vector = new DoubleVector2(x, y);
return vector;
}
#endregion
实际测试
设置控制点和原点
using FrameWorkSong;
using UnityEngine;
public class ChangePoint : MonoBehaviour
{
public DoubleVector2 TPoint;
public DoubleVector2 OPoint { get => GetOPoint();}
DoubleVector2 GetOPoint()
{
return new DoubleVector2(transform.position.x, transform.position.z);
}
}
在地图中设置控制
将经纬度坐标填入控制点的转换结果T,求出变换二项式
最后用一个测试点乘上变换二项式。测试结果。
误差取决于控制点和原点
using UnityEngine;
using FrameWorkSong;
using System.Collections.Generic;
public class ChangeMatrixMgr : MonoBehaviour
{
public ChangePoint Zreo;
public ChangePoint[] Points;
public ChangePoint test;
List<DoubleVector2> T;//转换后的向量
List<DoubleVector2> O;//转换前的向量
ChangeMatrixUtil changeMatrixUtil;
public DoubleVector4 TMatrix;
public DoubleVector4 OMatrix;
/// <summary>
/// 抽取坐标
/// </summary>
void ExtractionCoordinate()
{
T = new List<DoubleVector2>();
O = new List<DoubleVector2>();
int length = Points.Length;
for (int i = 0; i < length; i++)
{
T.Add(Points[i].TPoint - Zreo.TPoint);
O.Add(Points[i].OPoint - Zreo.OPoint);
}
}
void Start()
{
ExtractionCoordinate();
changeMatrixUtil = new ChangeMatrixUtil(T, O, 1);
TMatrix = changeMatrixUtil.TMatrix;
OMatrix = changeMatrixUtil.OMatrix;
test.TPoint = changeMatrixUtil.GetChangeVector(test.OPoint , changeMatrixUtil.TMatrix, Zreo.TPoint, Zreo.OPoint);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
ReadPiont();
}
if (Input.GetKeyDown(KeyCode.A))
{
test.TPoint= changeMatrixUtil.GetChangeVector(test.OPoint, changeMatrixUtil.TMatrix, Zreo.TPoint, Zreo.OPoint);
}
}
void ReadPiont()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit))
{
DoubleVector2 vector2 = changeMatrixUtil.GetChangeVector(GetVector(hit.point), changeMatrixUtil.TMatrix, Zreo.TPoint,Zreo.OPoint);
Debug.Log(vector2.x+"/"+ vector2.y);
}
}
DoubleVector2 GetVector(Vector3 vector3)
{
DoubleVector2 vector2 = new DoubleVector2(vector3.x, vector3.z);
return vector2;
}
}