using MathNet.Numerics.LinearAlgebra;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TeamAAS_VP.Core
{
///
/// 三点建立坐标系(或者原点及角度),并实现Local与Word坐标系直接的坐标互转换
///
public class CoordinateTransformer
{
///
/// 三个点建立坐标系时确定是以X轴作为基准还是Y轴作为基准
///
public enum Axis { X, Y };
///
/// P1 作为新坐标系的原点
///
public Vector P1 { get; }
///
/// 坐标系的基向量
///
public Vector E1 { get; }
///
/// 坐标系的基向量
///
public Vector E2 { get; }
public Matrix R { get; }
///
/// 旋转矩阵
///
public Matrix InvR { get; }
///
/// 平移矩阵
///
public Matrix T { get; }
///
/// 坐标系的旋转角度
///
public double Angle
{
get
{
//Vector2 e1 = new Vector2(Math.Cos(radians), Math.Sin(radians)); // 新x轴向量
//Vector2 e2 = new Vector2(-Math.Sin(radians), Math.Cos(radians)); // 新y轴向量
double thetaRand1 = Math.Asin(E1[1]);
double thetaDeg1 = thetaRand1 * 180 / Math.PI; // 将弧度值转换为角度值
return Math.Round(thetaDeg1, 3);
}
}
///
/// 三点建立坐标系,并实现Local与Word坐标系直接的坐标互转换
///
/// 原点X坐标
/// 原点Y坐标
/// X轴上的点X坐标
/// X轴上的点Y坐标
/// Y轴上的点X坐标
/// Y轴上的点Y坐标
/// 三个点建立坐标系时确定是以X轴作为基准还是Y轴作为基准
public CoordinateTransformer(double x1, double y1, double x2, double y2, double x3, double y3, Axis axis = Axis.X)
{
//假设我们有三个点 P1(x1, y1), P2(x2, y2), P3(x3, y3),它们是笛卡尔坐标系的三个点。我们要基于这三个点创建一个经过旋转和平移的坐标系,并且要求两个坐标系中的点可以互相转换。
//1.新坐标系的原点:我们可以将 P1 作为新坐标系的原点。因此,新坐标系的原点坐标为 (x1, y1)。
P1 = Vector.Build.Dense(new double[] { x1, y1 });
// Calculate basis vectors
Vector p2 = Vector.Build.Dense(new double[] { x2, y2 });
Vector p3 = Vector.Build.Dense(new double[] { x3, y3 });
//2.计算坐标系的基向量:
if (axis == Axis.X)
{
E1 = (p2 - P1) / (p2 - P1).L2Norm();
E2 = (p3 - P1 - E1.DotProduct(p3 - P1) * E1) / (p3 - P1 - E1.DotProduct(p3 - P1) * E1).L2Norm();
}
else
{
E2 = (p3 - P1) / (p3 - P1).L2Norm();
E1 = (p2 - P1 - E2.DotProduct(p2 - P1) * E2) / (p2 - P1 - E2.DotProduct(p2 - P1) * E2).L2Norm();
}
//3.计算旋转矩阵:我们可以使用基向量组成的矩阵作为旋转矩阵。具体地,我们可以将基向量 e1 和 e2 分别作为新坐标系下的 $x$ 和 $y$ 轴,然后组成一个矩阵,再对这个矩阵求逆即可得到旋转矩阵。代码实现:
// Compute rotation matrix
R = Matrix.Build.DenseOfColumnVectors(E1, E2);
InvR = R.Inverse();
//4.平移矩阵:由于我们选择的原点是 P1,因此我们需要对所有点进行平移,使得新坐标系的原点与笛卡尔坐标系的原点重合。具体地,我们可以使用以下平移矩阵:
// Compute translation matrix
T = Matrix.Build.DenseIdentity(3);
T[0, 2] = -P1[0];
T[1, 2] = -P1[1];
}
///
/// 三点建立坐标系,并实现Local与Word坐标系直接的坐标互转换
///
/// 原点坐标
/// X轴上的点坐标
/// Y轴上的点坐标
/// 三个点建立坐标系时确定是以X轴作为基准还是Y轴作为基准
public CoordinateTransformer(PointF Po, PointF Px, PointF Py, Axis axis = Axis.X)
{
//假设我们有三个点 P1(x1, y1), P2(x2, y2), P3(x3, y3),它们是笛卡尔坐标系的三个点。我们要基于这三个点创建一个经过旋转和平移的坐标系,并且要求两个坐标系中的点可以互相转换。
//1.新坐标系的原点:我们可以将 P1 作为新坐标系的原点。因此,新坐标系的原点坐标为 (x1, y1)。
P1 = Vector.Build.Dense(new double[] { Po.X, Po.Y });
// Calculate basis vectors
Vector p2 = Vector.Build.Dense(new double[] { Px.X, Px.Y });
Vector p3 = Vector.Build.Dense(new double[] { Py.X, Py.Y });
//2.计算坐标系的基向量:
if (axis == Axis.X)
{
E1 = (p2 - P1) / (p2 - P1).L2Norm();
E2 = (p3 - P1 - E1.DotProduct(p3 - P1) * E1) / (p3 - P1 - E1.DotProduct(p3 - P1) * E1).L2Norm();
}
else
{
E2 = (p3 - P1) / (p3 - P1).L2Norm();
E1 = (p2 - P1 - E2.DotProduct(p2 - P1) * E2) / (p2 - P1 - E2.DotProduct(p2 - P1) * E2).L2Norm();
}
//3.计算旋转矩阵:我们可以使用基向量组成的矩阵作为旋转矩阵。具体地,我们可以将基向量 e1 和 e2 分别作为新坐标系下的 $x$ 和 $y$ 轴,然后组成一个矩阵,再对这个矩阵求逆即可得到旋转矩阵。代码实现:
// Compute rotation matrix
R = Matrix.Build.DenseOfColumnVectors(E1, E2);
InvR = R.Inverse();
//4.平移矩阵:由于我们选择的原点是 P1,因此我们需要对所有点进行平移,使得新坐标系的原点与笛卡尔坐标系的原点重合。具体地,我们可以使用以下平移矩阵:
// Compute translation matrix
T = Matrix.Build.DenseIdentity(3);
T[0, 2] = -P1[0];
T[1, 2] = -P1[1];
}
///
/// 原点及角度建立坐标系
///
/// 原点坐标
/// 角度
public CoordinateTransformer(PointF Po, double theta)
{
double radians = theta * Math.PI / 180; // 将角度值转换为弧度值
//1.新坐标系的原点:我们可以将 P1 作为新坐标系的原点。因此,新坐标系的原点坐标为 (x1, y1)。
P1 = Vector.Build.Dense(new double[] { Po.X, Po.Y });
//2.计算坐标系的基向量:
E1 = Vector.Build.Dense(new double[] { Math.Cos(radians), Math.Sin(radians) }); // 新x轴向量
E2 = Vector.Build.Dense(new double[] { -Math.Sin(radians), Math.Cos(radians) }); // 新y轴向量
//3.计算旋转矩阵:我们可以使用基向量组成的矩阵作为旋转矩阵。具体地,我们可以将基向量 e1 和 e2 分别作为新坐标系下的 $x$ 和 $y$ 轴,然后组成一个矩阵,再对这个矩阵求逆即可得到旋转矩阵。代码实现:
// Compute rotation matrix
R = Matrix.Build.DenseOfColumnVectors(E1, E2);
InvR = R.Inverse();
//4.平移矩阵:由于我们选择的原点是 P1,因此我们需要对所有点进行平移,使得新坐标系的原点与笛卡尔坐标系的原点重合。具体地,我们可以使用以下平移矩阵:
// Compute translation matrix
T = Matrix.Build.DenseIdentity(3);
T[0, 2] = -P1[0];
T[1, 2] = -P1[1];
}
///
/// Word坐标系下的点转换成Local坐标系下的点
///
/// Word坐标系下的点X坐标
/// Word坐标系下的点Y坐标
/// 返回Local坐标系下的点
public Vector ToNewCoord(double x, double y)
{
Vector pOld = Vector.Build.Dense(new double[] { x, y });
Vector pNew = InvR * (pOld - P1);
return pNew;
}
///
/// Local坐标系下的点转换成Word坐标系下的点
///
/// Local坐标系下的点X坐标
/// Local坐标系下的点Y坐标
/// 返回Word坐标系下的点
public Vector ToOldCoord(double x, double y)
{
Vector pNew = Vector.Build.Dense(new double[] { x, y });
Vector pOld = R * pNew + P1;
return pOld;
}
}
}