C#实现坐标系转换

news2024/11/26 21:31:07

已知坐标系的向量线段AB,旋转指定角度后平移到达坐标A'B'

获取旋转角度以及新的其他坐标转换。

新建窗体应用程序CoordinateTransDemo,将默认的Form1重命名为FormCoordinateTrans,窗体设计如图:

窗体设计代码如下:

部分类文件FormCoordinateTrans.Designer.cs


namespace CoordinateTransDemo
{
    partial class FormCoordinateTrans
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要修改
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle();
            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle();
            this.rtxtMessage = new System.Windows.Forms.RichTextBox();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.txtCrd2Mark2_Y = new System.Windows.Forms.TextBox();
            this.label9 = new System.Windows.Forms.Label();
            this.label10 = new System.Windows.Forms.Label();
            this.txtCrd2Mark2_X = new System.Windows.Forms.TextBox();
            this.txtCrd2Mark1_Y = new System.Windows.Forms.TextBox();
            this.label11 = new System.Windows.Forms.Label();
            this.label12 = new System.Windows.Forms.Label();
            this.txtCrd2Mark1_X = new System.Windows.Forms.TextBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.txtCrd1Mark2_Y = new System.Windows.Forms.TextBox();
            this.label7 = new System.Windows.Forms.Label();
            this.label8 = new System.Windows.Forms.Label();
            this.txtCrd1Mark2_X = new System.Windows.Forms.TextBox();
            this.txtCrd1Mark1_Y = new System.Windows.Forms.TextBox();
            this.label6 = new System.Windows.Forms.Label();
            this.label5 = new System.Windows.Forms.Label();
            this.txtCrd1Mark1_X = new System.Windows.Forms.TextBox();
            this.dgvData = new System.Windows.Forms.DataGridView();
            this.btnTransform = new System.Windows.Forms.Button();
            this.dgvcPoleSequence = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.dgvcPoleX = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.dgvcPoleY = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.dgvcPoleAngle = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.dgvcTransformX = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.dgvcTransformY = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.groupBox2.SuspendLayout();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvData)).BeginInit();
            this.SuspendLayout();
            // 
            // rtxtMessage
            // 
            this.rtxtMessage.Location = new System.Drawing.Point(727, 12);
            this.rtxtMessage.Name = "rtxtMessage";
            this.rtxtMessage.Size = new System.Drawing.Size(491, 520);
            this.rtxtMessage.TabIndex = 22;
            this.rtxtMessage.Text = "";
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.Add(this.txtCrd2Mark2_Y);
            this.groupBox2.Controls.Add(this.label9);
            this.groupBox2.Controls.Add(this.label10);
            this.groupBox2.Controls.Add(this.txtCrd2Mark2_X);
            this.groupBox2.Controls.Add(this.txtCrd2Mark1_Y);
            this.groupBox2.Controls.Add(this.label11);
            this.groupBox2.Controls.Add(this.label12);
            this.groupBox2.Controls.Add(this.txtCrd2Mark1_X);
            this.groupBox2.Location = new System.Drawing.Point(255, 4);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(217, 120);
            this.groupBox2.TabIndex = 21;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "焊接Mark点坐标";
            // 
            // txtCrd2Mark2_Y
            // 
            this.txtCrd2Mark2_Y.Location = new System.Drawing.Point(108, 95);
            this.txtCrd2Mark2_Y.Name = "txtCrd2Mark2_Y";
            this.txtCrd2Mark2_Y.Size = new System.Drawing.Size(93, 21);
            this.txtCrd2Mark2_Y.TabIndex = 16;
            this.txtCrd2Mark2_Y.Text = "320.5";
            // 
            // label9
            // 
            this.label9.AutoSize = true;
            this.label9.Location = new System.Drawing.Point(10, 97);
            this.label9.Name = "label9";
            this.label9.Size = new System.Drawing.Size(89, 12);
            this.label9.TabIndex = 15;
            this.label9.Text = "焊接Mark2坐标Y";
            // 
            // label10
            // 
            this.label10.AutoSize = true;
            this.label10.Location = new System.Drawing.Point(10, 76);
            this.label10.Name = "label10";
            this.label10.Size = new System.Drawing.Size(89, 12);
            this.label10.TabIndex = 14;
            this.label10.Text = "焊接Mark2坐标X";
            // 
            // txtCrd2Mark2_X
            // 
            this.txtCrd2Mark2_X.Location = new System.Drawing.Point(108, 71);
            this.txtCrd2Mark2_X.Name = "txtCrd2Mark2_X";
            this.txtCrd2Mark2_X.Size = new System.Drawing.Size(93, 21);
            this.txtCrd2Mark2_X.TabIndex = 13;
            this.txtCrd2Mark2_X.Text = "120.5";
            // 
            // txtCrd2Mark1_Y
            // 
            this.txtCrd2Mark1_Y.Location = new System.Drawing.Point(108, 40);
            this.txtCrd2Mark1_Y.Name = "txtCrd2Mark1_Y";
            this.txtCrd2Mark1_Y.Size = new System.Drawing.Size(93, 21);
            this.txtCrd2Mark1_Y.TabIndex = 12;
            this.txtCrd2Mark1_Y.Text = "20.5";
            // 
            // label11
            // 
            this.label11.AutoSize = true;
            this.label11.Location = new System.Drawing.Point(10, 41);
            this.label11.Name = "label11";
            this.label11.Size = new System.Drawing.Size(89, 12);
            this.label11.TabIndex = 11;
            this.label11.Text = "焊接Mark1坐标Y";
            // 
            // label12
            // 
            this.label12.AutoSize = true;
            this.label12.Location = new System.Drawing.Point(10, 20);
            this.label12.Name = "label12";
            this.label12.Size = new System.Drawing.Size(89, 12);
            this.label12.TabIndex = 10;
            this.label12.Text = "焊接Mark1坐标X";
            // 
            // txtCrd2Mark1_X
            // 
            this.txtCrd2Mark1_X.Location = new System.Drawing.Point(108, 15);
            this.txtCrd2Mark1_X.Name = "txtCrd2Mark1_X";
            this.txtCrd2Mark1_X.Size = new System.Drawing.Size(93, 21);
            this.txtCrd2Mark1_X.TabIndex = 9;
            this.txtCrd2Mark1_X.Text = "20.5";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.txtCrd1Mark2_Y);
            this.groupBox1.Controls.Add(this.label7);
            this.groupBox1.Controls.Add(this.label8);
            this.groupBox1.Controls.Add(this.txtCrd1Mark2_X);
            this.groupBox1.Controls.Add(this.txtCrd1Mark1_Y);
            this.groupBox1.Controls.Add(this.label6);
            this.groupBox1.Controls.Add(this.label5);
            this.groupBox1.Controls.Add(this.txtCrd1Mark1_X);
            this.groupBox1.Location = new System.Drawing.Point(9, 4);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(217, 120);
            this.groupBox1.TabIndex = 20;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "拍照Mark点坐标";
            // 
            // txtCrd1Mark2_Y
            // 
            this.txtCrd1Mark2_Y.Location = new System.Drawing.Point(108, 95);
            this.txtCrd1Mark2_Y.Name = "txtCrd1Mark2_Y";
            this.txtCrd1Mark2_Y.Size = new System.Drawing.Size(93, 21);
            this.txtCrd1Mark2_Y.TabIndex = 16;
            this.txtCrd1Mark2_Y.Text = "110";
            // 
            // label7
            // 
            this.label7.AutoSize = true;
            this.label7.Location = new System.Drawing.Point(10, 97);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(89, 12);
            this.label7.TabIndex = 15;
            this.label7.Text = "拍照Mark2坐标Y";
            // 
            // label8
            // 
            this.label8.AutoSize = true;
            this.label8.Location = new System.Drawing.Point(10, 76);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(89, 12);
            this.label8.TabIndex = 14;
            this.label8.Text = "拍照Mark2坐标X";
            // 
            // txtCrd1Mark2_X
            // 
            this.txtCrd1Mark2_X.Location = new System.Drawing.Point(108, 71);
            this.txtCrd1Mark2_X.Name = "txtCrd1Mark2_X";
            this.txtCrd1Mark2_X.Size = new System.Drawing.Size(93, 21);
            this.txtCrd1Mark2_X.TabIndex = 13;
            this.txtCrd1Mark2_X.Text = "310";
            // 
            // txtCrd1Mark1_Y
            // 
            this.txtCrd1Mark1_Y.Location = new System.Drawing.Point(108, 40);
            this.txtCrd1Mark1_Y.Name = "txtCrd1Mark1_Y";
            this.txtCrd1Mark1_Y.Size = new System.Drawing.Size(93, 21);
            this.txtCrd1Mark1_Y.TabIndex = 12;
            this.txtCrd1Mark1_Y.Text = "10";
            // 
            // label6
            // 
            this.label6.AutoSize = true;
            this.label6.Location = new System.Drawing.Point(10, 41);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(89, 12);
            this.label6.TabIndex = 11;
            this.label6.Text = "拍照Mark1坐标Y";
            // 
            // label5
            // 
            this.label5.AutoSize = true;
            this.label5.Location = new System.Drawing.Point(10, 20);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(89, 12);
            this.label5.TabIndex = 10;
            this.label5.Text = "拍照Mark1坐标X";
            // 
            // txtCrd1Mark1_X
            // 
            this.txtCrd1Mark1_X.Location = new System.Drawing.Point(108, 15);
            this.txtCrd1Mark1_X.Name = "txtCrd1Mark1_X";
            this.txtCrd1Mark1_X.Size = new System.Drawing.Size(93, 21);
            this.txtCrd1Mark1_X.TabIndex = 9;
            this.txtCrd1Mark1_X.Text = "10";
            // 
            // dgvData
            // 
            this.dgvData.AllowUserToAddRows = false;
            this.dgvData.AllowUserToDeleteRows = false;
            this.dgvData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dgvData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
            this.dgvcPoleSequence,
            this.dgvcPoleX,
            this.dgvcPoleY,
            this.dgvcPoleAngle,
            this.dgvcTransformX,
            this.dgvcTransformY});
            this.dgvData.Location = new System.Drawing.Point(5, 129);
            this.dgvData.Name = "dgvData";
            this.dgvData.ReadOnly = true;
            this.dgvData.RowHeadersWidth = 25;
            this.dgvData.RowTemplate.Height = 23;
            this.dgvData.Size = new System.Drawing.Size(717, 403);
            this.dgvData.TabIndex = 19;
            // 
            // btnTransform
            // 
            this.btnTransform.Font = new System.Drawing.Font("宋体", 16F);
            this.btnTransform.ForeColor = System.Drawing.Color.Blue;
            this.btnTransform.Location = new System.Drawing.Point(505, 12);
            this.btnTransform.Name = "btnTransform";
            this.btnTransform.Size = new System.Drawing.Size(127, 45);
            this.btnTransform.TabIndex = 23;
            this.btnTransform.Text = "坐标转换";
            this.btnTransform.UseVisualStyleBackColor = true;
            this.btnTransform.Click += new System.EventHandler(this.btnTransform_Click);
            // 
            // dgvcPoleSequence
            // 
            this.dgvcPoleSequence.HeaderText = "极柱序号";
            this.dgvcPoleSequence.Name = "dgvcPoleSequence";
            this.dgvcPoleSequence.ReadOnly = true;
            this.dgvcPoleSequence.Width = 80;
            // 
            // dgvcPoleX
            // 
            this.dgvcPoleX.HeaderText = "极柱X坐标";
            this.dgvcPoleX.Name = "dgvcPoleX";
            this.dgvcPoleX.ReadOnly = true;
            // 
            // dgvcPoleY
            // 
            this.dgvcPoleY.HeaderText = "极柱Y坐标";
            this.dgvcPoleY.Name = "dgvcPoleY";
            this.dgvcPoleY.ReadOnly = true;
            // 
            // dgvcPoleAngle
            // 
            this.dgvcPoleAngle.HeaderText = "极柱角度Z";
            this.dgvcPoleAngle.Name = "dgvcPoleAngle";
            this.dgvcPoleAngle.ReadOnly = true;
            // 
            // dgvcTransformX
            // 
            dataGridViewCellStyle5.ForeColor = System.Drawing.Color.Red;
            this.dgvcTransformX.DefaultCellStyle = dataGridViewCellStyle5;
            this.dgvcTransformX.HeaderText = "转换后X坐标";
            this.dgvcTransformX.Name = "dgvcTransformX";
            this.dgvcTransformX.ReadOnly = true;
            this.dgvcTransformX.Width = 130;
            // 
            // dgvcTransformY
            // 
            dataGridViewCellStyle6.ForeColor = System.Drawing.Color.Red;
            this.dgvcTransformY.DefaultCellStyle = dataGridViewCellStyle6;
            this.dgvcTransformY.HeaderText = "转换后Y坐标";
            this.dgvcTransformY.Name = "dgvcTransformY";
            this.dgvcTransformY.ReadOnly = true;
            this.dgvcTransformY.Width = 130;
            // 
            // FormCoordinateTrans
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1238, 544);
            this.Controls.Add(this.btnTransform);
            this.Controls.Add(this.rtxtMessage);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.dgvData);
            this.Name = "FormCoordinateTrans";
            this.Text = "坐标转换-斯内科";
            this.Load += new System.EventHandler(this.FormCoordinateTrans_Load);
            this.groupBox2.ResumeLayout(false);
            this.groupBox2.PerformLayout();
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvData)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.RichTextBox rtxtMessage;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.TextBox txtCrd2Mark2_Y;
        private System.Windows.Forms.Label label9;
        private System.Windows.Forms.Label label10;
        private System.Windows.Forms.TextBox txtCrd2Mark2_X;
        private System.Windows.Forms.TextBox txtCrd2Mark1_Y;
        private System.Windows.Forms.Label label11;
        private System.Windows.Forms.Label label12;
        private System.Windows.Forms.TextBox txtCrd2Mark1_X;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox txtCrd1Mark2_Y;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.TextBox txtCrd1Mark2_X;
        private System.Windows.Forms.TextBox txtCrd1Mark1_Y;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.TextBox txtCrd1Mark1_X;
        private System.Windows.Forms.DataGridView dgvData;
        private System.Windows.Forms.Button btnTransform;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcPoleSequence;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcPoleX;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcPoleY;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcPoleAngle;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcTransformX;
        private System.Windows.Forms.DataGridViewTextBoxColumn dgvcTransformY;
    }
}

新建坐标结构Coord

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoordinateTransDemo
{
    /// <summary>
    /// 表示三维坐标系的一个坐标(x,y,z)
    /// </summary>
    public struct Coord
    {
        /// <summary>
        /// X坐标,一般是左右方向的轴X
        /// </summary>
        public double X;
        /// <summary>
        /// Y坐标,一般是前后方向的轴Y
        /// </summary>
        public double Y;
        /// <summary>
        /// Z坐标,一般是垂直高度【上下】方向的轴Z,有时也用角度Angle表示
        /// </summary>
        public double Z;
        public Coord(double x = 0, double y = 0, double z = 0) 
        {
            X = x;
            Y = y;
            Z = z;
        }

        /// <summary>
        /// 判断两个坐标是否重合【是否是同一个点】
        /// </summary>
        /// <param name="coord1"></param>
        /// <param name="coord2"></param>
        /// <returns></returns>
        public static bool operator ==(Coord coord1, Coord coord2) 
        {
            return coord1.X == coord2.X && coord1.Y == coord2.Y && coord1.Z == coord2.Z;
        }

        /// <summary>
        /// 判断两个坐标是否不重合【不同的坐标点】
        /// </summary>
        /// <param name="coord1"></param>
        /// <param name="coord2"></param>
        /// <returns></returns>
        public static bool operator !=(Coord coord1, Coord coord2)
        {
            return coord1.X != coord2.X || coord1.Y != coord2.Y || coord1.Z != coord2.Z;
        }

        /// <summary>
        /// 打印坐标,返回坐标字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"({X},{Y},{Z})";
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}

新建关键的坐标转换类CoordinateTransHelper

关键算法代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoordinateTransDemo
{
    /// <summary>
    /// 坐标转换的算法
    /// 斯内科Snake
    /// </summary>
    public class CoordinateTransHelper
    {
        /// <summary>
        /// 坐标系1是标准坐标系
        /// 坐标系2相对于坐标系1MARK点距离差值的最大值
        /// </summary>
        public static double Max_MarkDistanceDIF = 1;
        /// <summary>
        /// 计算坐标系2相对于坐标系1的旋转角,结果是弧度
        /// </summary>
        public static double Crd2ToCrd1Angle = 0;

        /// <summary>
        /// 坐标转换方法【单个】
        /// </summary>
        /// <param name="Crd2Mark1">坐标系2的Mark1的点坐标</param>
        /// <param name="Crd2Mark2">坐标系2的Mark2的点坐标</param>
        /// <param name="Crd1Mark1">坐标系1的Mark1的点坐标</param>
        /// <param name="Crd1Mark2">坐标系1的Mark2的点坐标</param>
        /// <param name="InPoint">需要转换的初始坐标</param>
        /// <param name="OutPoint">转换后的结果坐标</param>
        /// <returns></returns>
        public static bool GetCalcCoordCoordinate(Coord Crd2Mark1, Coord Crd2Mark2, Coord Crd1Mark1, Coord Crd1Mark2, Coord InPoint, out Coord OutPoint, out string errorMsg)
        {
            errorMsg = string.Empty;
            OutPoint = new Coord();
            OutPoint.X = 0;
            OutPoint.Y = 0;
            try
            {                
                Crd2ToCrd1Angle = GetRotateAngle(Crd2Mark1, Crd2Mark2, Crd1Mark1, Crd1Mark2);
                //计算坐标系2相对于坐标系1的缩放系数
                double Crd2ToCrd1Zoom =
                     Math.Sqrt(Math.Pow((Crd2Mark1.X - Crd2Mark2.X), 2) + Math.Pow((Crd2Mark1.Y - Crd2Mark2.Y), 2))
                    /
                    Math.Sqrt(Math.Pow((Crd1Mark1.X - Crd1Mark2.X), 2) + Math.Pow((Crd1Mark1.Y - Crd1Mark2.Y), 2));

                //输出坐标计算
                OutPoint.X = ((InPoint.X - Crd1Mark1.X) * Math.Cos(Crd2ToCrd1Angle) - (InPoint.Y - Crd1Mark1.Y) * Math.Sin(Crd2ToCrd1Angle)) * Crd2ToCrd1Zoom + Crd2Mark1.X;
                OutPoint.Y = ((InPoint.X - Crd1Mark1.X) * Math.Sin(Crd2ToCrd1Angle) + (InPoint.Y - Crd1Mark1.Y) * Math.Cos(Crd2ToCrd1Angle)) * Crd2ToCrd1Zoom + Crd2Mark1.Y;

                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "计算异常:" + ex.Message + ex.StackTrace;
                return false;
            }
        }

        /// <summary>
        /// 坐标转换方法【批量】
        /// </summary>
        /// <param name="Crd2Mark1">坐标系2的Mark1的点坐标</param>
        /// <param name="Crd2Mark2">坐标系2的Mark2的点坐标</param>
        /// <param name="Crd1Mark1">坐标系1的Mark1的点坐标</param>
        /// <param name="Crd1Mark2">坐标系1的Mark2的点坐标</param>
        /// <param name="InPoint">需要转换的初始坐标集合</param>
        /// <param name="OutPoint">转换后的结果坐标集合</param>
        public static bool GetCalcCoordCoordinate(Coord Crd2Mark1, Coord Crd2Mark2, Coord Crd1Mark1, Coord Crd1Mark2, Coord[] InPointArray, out Coord[] OutPointArray,out string errorMessage) 
        {
            errorMessage = string.Empty;
            OutPointArray = new Coord[0];
            if (InPointArray == null || InPointArray.Length == 0) 
            {
                errorMessage = "需要转化的源坐标数组不能为空";
                return false;
            }
            OutPointArray = new Coord[InPointArray.Length];
            Crd2ToCrd1Angle = GetRotateAngle(Crd2Mark1, Crd2Mark2, Crd1Mark1, Crd1Mark2);
            //计算坐标系2相对于坐标系1的缩放系数
            double Crd2ToCrd1Zoom =
                 Math.Sqrt(Math.Pow((Crd2Mark1.X - Crd2Mark2.X), 2) + Math.Pow((Crd2Mark1.Y - Crd2Mark2.Y), 2))
                /
                Math.Sqrt(Math.Pow((Crd1Mark1.X - Crd1Mark2.X), 2) + Math.Pow((Crd1Mark1.Y - Crd1Mark2.Y), 2));
            Coord OutPoint;
            for (int i = 0; i < OutPointArray.Length; i++)
            {
                Coord InPoint = InPointArray[i];
                OutPoint = new Coord();

                //输出坐标计算
                OutPoint.X = ((InPoint.X - Crd1Mark1.X) * Math.Cos(Crd2ToCrd1Angle) - (InPoint.Y - Crd1Mark1.Y) * Math.Sin(Crd2ToCrd1Angle)) * Crd2ToCrd1Zoom + Crd2Mark1.X;
                OutPoint.Y = ((InPoint.X - Crd1Mark1.X) * Math.Sin(Crd2ToCrd1Angle) + (InPoint.Y - Crd1Mark1.Y) * Math.Cos(Crd2ToCrd1Angle)) * Crd2ToCrd1Zoom + Crd2Mark1.Y;
                OutPointArray[i] = OutPoint;
            }
            return true;
        }

        /// <summary>
        /// 计算坐标系2相对于坐标系1的旋转角,结果是弧度
        /// </summary>
        /// <param name="Crd2Mark1"></param>
        /// <param name="Crd2Mark2"></param>
        /// <param name="Crd1Mark1"></param>
        /// <param name="Crd1Mark2"></param>
        /// <returns></returns>
        public static double GetRotateAngle(Coord Crd2Mark1, Coord Crd2Mark2, Coord Crd1Mark1, Coord Crd1Mark2) 
        {
            if (Crd1Mark1 == Crd1Mark2 || Crd2Mark1 == Crd2Mark2)
            {
                throw new Exception("请检查参数配置,Mark点不能重合");
            }
            //计算坐标系2相对于坐标系1MARK点距离差值
            double MarkDistanceDIF = 0;//线段的长度进行比较
            MarkDistanceDIF = Math.Sqrt(Math.Pow((Crd2Mark1.X - Crd2Mark2.X), 2) + Math.Pow((Crd2Mark1.Y - Crd2Mark2.Y), 2))
               - Math.Sqrt(Math.Pow((Crd1Mark1.X - Crd1Mark2.X), 2) + Math.Pow((Crd1Mark1.Y - Crd1Mark2.Y), 2));

            if (Math.Abs(MarkDistanceDIF) > Math.Abs(Max_MarkDistanceDIF))
            {
                throw new Exception($"坐标系2相对于坐标系1MARK点距离差值:{MarkDistanceDIF},大于限制值:{Max_MarkDistanceDIF}");
            }
            //类似于将线段AB平移到原点开始变成线段OP,与 X轴正方向的夹角∠POX
            //线段向量OP共有8种可能:第一象限,第二象限,第三象限,第四象限,X+,Y+,X-,Y-
            double Crd1DertaX = Crd1Mark2.X - Crd1Mark1.X;
            double Crd1DertaY = Crd1Mark2.Y - Crd1Mark1.Y;
            double Crd2DertaX = Crd2Mark2.X - Crd2Mark1.X;
            double Crd2DertaY = Crd2Mark2.Y - Crd2Mark1.Y;

            double Crd1Angle = 0;
            //坐标系1的MARK点连成的直线指向第一象限
            if (Crd1DertaX > 0 && Crd1DertaY > 0)
            {
                Crd1Angle = Math.Abs(Math.Atan((Crd1Mark2.Y - Crd1Mark1.Y) / (Crd1Mark2.X - Crd1Mark1.X)));
            }
            else
            {
                
            }

            //坐标系1的MARK点连成的直线指向第二象限
            if (Crd1DertaX < 0 && Crd1DertaY > 0)
            {
                Crd1Angle = (180 * Math.PI / 180) - Math.Abs(Math.Atan((Crd1Mark2.Y - Crd1Mark1.Y) / (Crd1Mark2.X - Crd1Mark1.X)));
            }
            else
            {

            }

            //坐标系1的MARK点连成的直线指向第三象限
            if (Crd1DertaX < 0 && Crd1DertaY < 0)
            {
                Crd1Angle = (180 * Math.PI / 180) + Math.Abs(Math.Atan((Crd1Mark2.Y - Crd1Mark1.Y) / (Crd1Mark2.X - Crd1Mark1.X)));
            }
            else
            {

            }

            //坐标系1的MARK点连成的直线指向第四象限
            if (Crd1DertaX > 0 && Crd1DertaY < 0)
            {
                Crd1Angle = (360 * Math.PI / 180) - Math.Abs(Math.Atan((Crd1Mark2.Y - Crd1Mark1.Y) / (Crd1Mark2.X - Crd1Mark1.X)));
            }
            else
            {

            }
            
            double Crd2Angle = 0;
            //坐标系2的MARK点连成的直线指向第一象限
            if (Crd2DertaX > 0 && Crd2DertaY > 0)
            {
                Crd2Angle = Math.Abs(Math.Atan((Crd2Mark2.Y - Crd2Mark1.Y) / (Crd2Mark2.X - Crd2Mark1.X)));
            }
            else
            {

            }

            //坐标系2的MARK点连成的直线指向第二象限
            if (Crd2DertaX < 0 && Crd2DertaY > 0)
            {
                Crd2Angle = (180 * Math.PI / 180) - Math.Abs(Math.Atan((Crd2Mark2.Y - Crd2Mark1.Y) / (Crd2Mark2.X - Crd2Mark1.X)));
            }
            else
            {

            }

            //坐标系2的MARK点连成的直线指向第三象限
            if (Crd2DertaX < 0 && Crd2DertaY < 0)
            {
                Crd2Angle = (180 * Math.PI / 180) + Math.Abs(Math.Atan((Crd2Mark2.Y - Crd2Mark1.Y) / (Crd2Mark2.X - Crd2Mark1.X)));
            }
            else
            {

            }

            //坐标系2的MARK点连成的直线指向第四象限
            if (Crd2DertaX > 0 && Crd2DertaY < 0)
            {
                Crd2Angle = (360 * Math.PI / 180) - Math.Abs(Math.Atan((Crd2Mark2.Y - Crd2Mark1.Y) / (Crd2Mark2.X - Crd2Mark1.X)));
            }
            else
            {

            }

            //坐标系1的MARK点连成的直线倾角是0度,即X+
            if (Crd1DertaX > 0 && Crd1DertaY == 0)
            {
                Crd1Angle = 0;
            }

            //坐标系1的MARK点连成的直线倾角是90度,即Y+
            if (Crd1DertaX == 0 && Crd1DertaY > 0)
            {
                Crd1Angle = (90 * Math.PI / 180);
            }

            //坐标系1的MARK点连成的直线倾角是180度,即X-
            if (Crd1DertaX < 0 && Crd1DertaY == 0)
            {
                Crd1Angle = (180 * Math.PI / 180);
            }

            //坐标系1的MARK点连成的直线倾角是270度,即Y-
            if (Crd1DertaX == 0 && Crd1DertaY < 0)
            {
                Crd1Angle = (270 * Math.PI / 180);
            }
            
            //坐标系2的MARK点连成的直线倾角是0度
            if (Crd2DertaX > 0 && Crd2DertaY == 0)
            {
                Crd2Angle = 0;
            }

            //坐标系2的MARK点连成的直线倾角是90度
            if (Crd2DertaX == 0 && Crd2DertaY > 0)
            {
                Crd2Angle = (90 * Math.PI / 180);
            }

            //坐标系2的MARK点连成的直线倾角是180度
            if (Crd2DertaX < 0 && Crd2DertaY == 0)
            {
                Crd2Angle = (180 * Math.PI / 180);
            }

            //坐标系2的MARK点连成的直线倾角是270度
            if (Crd2DertaX == 0 && Crd2DertaY < 0)
            {
                Crd2Angle = (270 * Math.PI / 180);
            }

            //计算坐标系2相对于坐标系1的旋转角,结果是弧度
            Crd2ToCrd1Angle = Crd2Angle - Crd1Angle;
            return Crd2ToCrd1Angle;
        }
    }
}

测试坐标转换代码如下:

文件FormCoordinateTrans.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CoordinateTransDemo
{
    public partial class FormCoordinateTrans : Form
    {
        public FormCoordinateTrans()
        {
            InitializeComponent();

            //转换坐标为红色
            dgvcTransformX.HeaderCell.Style.ForeColor = Color.Red;
            dgvcTransformY.HeaderCell.Style.ForeColor = Color.Red;
            this.dgvData.EnableHeadersVisualStyles = false;
            rtxtMessage.ReadOnly = true;
        }

        private void FormCoordinateTrans_Load(object sender, EventArgs e)
        {
            dgvData.Rows.Clear();
            int poleCount = 10;
            Coord[] photoCoords = new Coord[poleCount];
            photoCoords[0] = new Coord(123, 34.68);
            photoCoords[1] = new Coord(222.1, 222.2);
            photoCoords[2] = new Coord(333.11, 333.22);
            photoCoords[3] = new Coord(-1, -8.23);
            photoCoords[4] = new Coord(234, -345.3);
            photoCoords[5] = new Coord(-80, 125);
            photoCoords[6] = new Coord(-90, 0);
            photoCoords[7] = new Coord(0, 180);
            for (int i = 0; i < poleCount; i++)
            {
                dgvData.Rows.Add(i + 1, photoCoords[i].X, photoCoords[i].Y, photoCoords[i].Z, 0.0F, 0.0F);
            }
        }

        private void btnTransform_Click(object sender, EventArgs e)
        {
            Coord[] inPointArray = new Coord[dgvData.Rows.Count];
            for (int i = 0; i < dgvData.Rows.Count; i++)
            {
                inPointArray[i] = new Coord(Convert.ToSingle(dgvData["dgvcPoleX", i].Value),
                Convert.ToSingle(dgvData["dgvcPoleY", i].Value),
                Convert.ToSingle(dgvData["dgvcPoleAngle", i].Value));
            }

            string errorMessage;
            Coord[] outPointArray;
            Coord Crd2Mark1 = new Coord(double.Parse(txtCrd2Mark1_X.Text), double.Parse(txtCrd2Mark1_Y.Text));
            Coord Crd2Mark2 = new Coord(double.Parse(txtCrd2Mark2_X.Text), double.Parse(txtCrd2Mark2_Y.Text));
            Coord Crd1Mark1 = new Coord(double.Parse(txtCrd1Mark1_X.Text), double.Parse(txtCrd1Mark1_Y.Text));
            Coord Crd1Mark2 = new Coord(double.Parse(txtCrd1Mark2_X.Text), double.Parse(txtCrd1Mark2_Y.Text));
            bool result = CoordinateTransHelper.GetCalcCoordCoordinate(Crd2Mark1, Crd2Mark2, Crd1Mark1, Crd1Mark2, inPointArray, out outPointArray, out errorMessage);
            double rotateAngle = CoordinateTransHelper.Crd2ToCrd1Angle * 180 / Math.PI;
            DisplayMessage($"获取转换后的坐标操作结果:【{result}】,旋转角度【{rotateAngle}°】,旋转弧度【{CoordinateTransHelper.Crd2ToCrd1Angle}】");
            for (int i = 0; i < dgvData.Rows.Count; i++)
            {
                float srcPoleX = Convert.ToSingle(dgvData["dgvcPoleX", i].Value);
                float srcPoleY = Convert.ToSingle(dgvData["dgvcPoleY", i].Value);
                if (srcPoleX == 0 && srcPoleY == 0)
                {
                    //如果坐标是(0,0)认为是无效坐标
                    dgvData["dgvcTransformX", i].Value = 0;
                    dgvData["dgvcTransformY", i].Value = 0;
                    continue;
                }
                dgvData["dgvcTransformX", i].Value = outPointArray[i].X;
                dgvData["dgvcTransformY", i].Value = outPointArray[i].Y;
            }
        }
        /// <summary>
        /// 显示推送消息
        /// </summary>
        /// <param name="msg"></param>
        private void DisplayMessage(string msg)
        {
            this.BeginInvoke(new Action(() =>
            {
                if (rtxtMessage.TextLength > 20480)
                {
                    rtxtMessage.Clear();
                }
                rtxtMessage.AppendText($"{DateTime.Now.ToString("HH:mm:ss.fff")}->{msg}\n");
                rtxtMessage.ScrollToCaret();
            }));
        }
    }
}

运行如图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1433256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在windows下安装docker部署环境运行项目----docker-compose.yml

前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01; 也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(六)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十四章&#xff1a;使用卷积神经网络进行深度计算机视觉 尽管 IBM 的 Deep Blue 超级计算机在 1996 年击败了国际象棋世界冠军…

力扣 第 383 场周赛 解题报告 | 珂学家 | Z函数/StringHash

前言 谁言别后终无悔 寒月清宵绮梦回 深知身在情长在 前尘不共彩云飞 整体评价 T3是道模拟题&#xff0c;但是感觉题意有些晦涩&#xff0c;T4一眼Z函数&#xff0c;当然StringHash更通用些。 新年快乐, _. T1. 将单词恢复初始状态所需的最短时间 I 思路: 模拟 就是前缀和为…

AI助力农作物自动采摘,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建作物生产场景下番茄采摘检测计数分析系统

去年十一那会无意间刷到一个视频展示的就是德国机械收割机非常高效自动化地24小时不间断地在超广阔的土地上采摘各种作物&#xff0c;专家设计出来了很多用于采摘不同农作物的大型机械&#xff0c;看着非常震撼&#xff0c;但是我们国内农业的发展还是相对比较滞后的&#xff0…

BUUCTF-Real-[PHPMYADMIN]CVE-2018-12613

目录 漏洞背景介绍 漏洞产生 漏洞利用 漏洞验证 漏洞背景介绍 phpMyAdmin 是一个以PHP为基础&#xff0c;以Web-Base方式架构在网站主机上的MySQL的数据库管理工具&#xff0c;让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳…

GPT如何在一分钟内完成论文数据分析?

数据上传 PPMAN-AI 01 由于技术限制&#xff0c;目前InfinitePaper AI仅支持上传1份文件&#xff0c;且大小不超过10M。但是&#xff0c;在强大的代码解释器面前&#xff0c;这都是小问题。我们只需要将可能用到的文件打包成压缩文件上传即可&#xff0c;之后要求GPT直接解压…

计算机设计大赛 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

财务数据处理问题及解决方案分享

一、平台介绍 财务自营计费主要承接京东自营数据在整个供应链中由C端转B端的功能实现&#xff0c;在整个供应链中属于靠后的阶段了&#xff0c;系统主要功能是计费和向B端的汇总。 二、问题描述 近年来自营计费数据量大增&#xff0c;有百亿的数据量&#xff0c;一天中汇总占…

Docker进阶篇-compose容器编排

一、描述 Docker-Compose是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。 Compose是Docker公司推出的一个工具软件&#xff0c;可以管理多个Docker容器组成一个应用。需要定义 一个YAML格式的配置文件docker-compose.yml&#xff0c;配置好多个容器…

Stable Diffusion 模型下载:国风3 GuoFeng3

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十推荐提示词下载地址模型介绍 欢迎使用GuoFeng3模型 - 这是一个中国华丽古风风格模型,也可以说是一个古风游戏角色模型,具有2.5D的质感。 条目内

【UE Niagara】环绕在人物周围的闪电效果

效果 步骤 1. 首先下载一个螺旋形状的静态网格体并导入UE&#xff08;地址&#xff1a;https://pan.baidu.com/s/1l9Bn5lQd7tDBu3CMs4c2aA?pwd7myr &#xff09; 2. 创建一个Niagara系统 使用Empty模板 这里命名为“NS_LightingAround” 打开“NS_LightingAround”&#xff0…

Matplotlib绘制炫酷柱状图的艺术与技巧【第60篇—python:Matplotlib绘制柱状图】

文章目录 Matplotlib绘制炫酷柱状图的艺术与技巧1. 簇状柱状图2. 堆积柱状图3. 横向柱状图4. 百分比柱状图5. 3D柱状图6. 堆积横向柱状图7. 多系列百分比柱状图8. 3D堆积柱状图9. 带有误差线的柱状图10. 分组百分比柱状图11. 水平堆积柱状图12. 多面板柱状图13. 自定义颜色和样…

STC系列单片机的中断系统

目录 一、中断系统的定义 二、STC15系列单片机的中断请求源及结构图 三、中断查询表以及触发方式 四、在keil c中如何声明中断函数 五、外部中断 六、基于STC15芯片实战中断系统的使用 &#xff08;1&#xff09;外部中断2/外部中断3来检测门的开关状态 &#xff08;2&a…

Centos 内存和硬盘占用情况以及top作用

目录 只查看内存使用情况&#xff1a; 内存使用排序取前5个&#xff1a; 硬盘占用情况 定位占用空间最大目录 top查看cpu及内存使用信息 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

RK3399平台开发系列讲解(内存篇)进程内存详解

🚀返回专栏总目录 文章目录 一、虚拟地址映射的物理内存1.1、物理内存1.2、虚拟内存1.2.1、用户态:低特权运行程序1.2.2、内核态:运行的程序需要访问操作系统内核数据二、PageCache三、指标查询命令沉淀、分享、成长,让自己和他人都能有所收获!😄 📢进程消耗的内存包…

车载充电器(OBC)氮化镓(GaN)驱动(高压高功率)设计(第四篇)

上图来自于网络 1、GaN FET概念 GaN FET&#xff0c;全称为Gallium Nitride Field-Effect Transistor&#xff08;氮化镓场效应晶体管&#xff09;&#xff0c;是一种采用氮化镓&#xff08;Gallium Nitride, GaN&#xff09;材料制作的新型功率半导体器件。相较于传统的硅基…

『运维备忘录』之 Cron 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

Vue学习笔记之组件基础

1、组件的定义 一般将 Vue 组件定义在一个单独的 .vue 文件中&#xff0c;称做单文件组件&#xff1b;当然也可以将组件直接定义在js文件中&#xff0c;如下js代码&#xff0c;定义一个组件BlogPost&#xff0c;通过props定义对外暴露属性title&#xff0c;父组件传递title&am…

MySQL 小技巧:xtrabackup 软件包的下载及安装

案例&#xff1a;xtrabackup 软件包的下载及安装 软件包下载&#xff1a;Index of /percona/centos/7/RPMS/x86_64/ CentOS7 默认的数据库版本比较老,因此建议使用 xtrabackup 2.4 版本 // CentOS7 默认的数据库版本比较老,因此建议使用 xtrabackup 2.4 版本 // 安装 CentOS7 默…

【算法与数据结构】647、516、LeetCode回文子串+最长回文子序列

文章目录 一、647、回文子串二、516、最长回文子序列三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、647、回文子串 思路分析&#xff1a;判断一个字符串是否为回文串那么必须确定回文串的所在区间&#xff0c;而一维…