【Unity】坐标转换经纬度方法(原理篇)

Unity坐标转换经纬度方法(线性变换)

Demo下载
Demo的使用方法

解决问题

针对缩放,旋转,翻转的两套坐标系转换。

线性变换原理

所有的线性坐标转换都是其基坐标的缩放和旋转。

变换公式

∣ 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=aOi+bOj
T j = c ∗ O i + d ∗ O j T_j= c* O_i+d* O_j Tj=cOi+dOj

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=aO1i+bO1jT2i=aO2i+bO2j
{ 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=cO1i+dO1jT2j=cO2i+dO2j

行列式应用

      #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;
    }
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小生云木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值