C#实现坐标系转换

已知坐标系的向量线段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);}#endregionprivate 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.rhkb.cn/news/251888.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

群晖NAS开启FTP服务结合内网穿透实现公网远程访问本地服务

⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 文章目录 ⛳️ 推荐1. 群晖安装Cpolar2. 创建FTP公网地址3. 开启群晖FTP服务4. 群晖FTP远程连接5. 固定FTP公网地址6. 固定FTP…

C# wpf 字体图标预览,html字符与unicode转换

在进行wpf 开发工作过程中遇到字体图标无法预览的问题&#xff0c;特此记录。 1、把需要预览的字体文件上传到网站上进行转换 Create Your Own font-face Kits Font Squirrel2、下载文件后进行解压。 3、找到 Glyph Chart 查看字体html字符编码4、在wpf中直接使用即可 <…

削峰有高招!评价QPS降低85%的背后逻辑-京东零售技术实践

一、背景 京东APP商品详情页展示的评价数据通过单独请求评价接口获取&#xff0c;与商详模块流量近乎1:1&#xff0c;需要共同应对秒杀等海量流量的冲击&#xff0c;存在突发流量风险。经过对用户操作行为和评价埋点信息分析&#xff0c;评价调用与商详流量解耦可行&#xff0…

自动驾驶IPO第一股及商业化行业标杆 Mobileye

一、Mobileye 简介 Mobileye 是全球领先的自动驾驶技术公司&#xff0c;成立于 1999 年&#xff0c;总部位于以色列耶路撒冷。公司专注于开发视觉感知技术和辅助驾驶系统 (ADAS)&#xff0c;并在自动驾驶领域处于领先地位。Mobileye 是高级驾驶辅助系统&#xff08;ADAS&#…

Mac利用brew安装mysql并设置初始密码

前言 之前一直是在windows上开发后段程序&#xff0c;所以只在windows上装mysql。(我记得linux只需要适应yum之类的命令即可) 安装mysql brew install mysql等它装完就好啦 开启mysql mysql.server start顺带一提&#xff0c;关闭命令是 mysql.server stop设置初始密码 …

[opencvsharp]C#基于Fast算法实现角点检测

角点检测算法有很多&#xff0c;比如Harris角点检测、Shi-Tomas算法、sift算法、SURF算法、ORB算法、BRIEF算法、Fast算法等&#xff0c;今天我们使用C#的opencvsharp库实现Fast角点检测 【算法介绍】 fast算法 Fast(全称Features from accelerated segment test)是一种用于角…

WordPress主题YIA如何将首页的置顶小工具改为站长推荐小工具?

YIA主题有“置顶推荐”小工具&#xff0c;首页文章列表页有置顶功能&#xff0c;可在YIA主题设置 >> 列表 >> 首页-最新发布 >> 显示置顶文章中开启或关闭。如果将“置顶推荐”小工具添加到“首页顶栏”&#xff0c;同时也开启首页最新发布的“显示置顶文章”…

【产业实践】使用YOLO V5 训练自有数据集,并且在C# Winform上通过onnx模块进行预测全流程打通

使用YOLO V5 训练自有数据集,并且在C# Winform上通过onnx模块进行预测全流程打通 效果图 背景介绍 当谈到目标检测算法时,YOLO(You Only Look Once)系列算法是一个备受关注的领域。YOLO通过将目标检测任务转化为一个回归问题,实现了快速且准确的目标检测。以下是YOLO的基…

【JavaScript + CSS】随机生成十六进制颜色

效果图 实现 <template><div class"year_area"><div class"year_list"><el-row :span"24"><div :class"showAll"><el-col :span"5" v-for"(item, index) in defaulList" :key&…

Office恢复旧UI|Office UI问题|Word UI|小喇叭找不到

Office恢复旧UI&#xff5c;Office UI问题&#xff5c;Word UI&#xff5c;小喇叭找不到 问题描述&#xff1a;Office新版本默认新UI&#xff0c;主界面没有小喇叭可以切换到旧UI. 解决方案&#xff1a; 以下述内容新建.txt&#xff0c;保存并改后缀为.reg&#xff0c;双击打开…

redis下载与安装教程(centos下)

文章目录 一&#xff0c;redis下载1.1上传到linux服务器上 二&#xff0c;redis安装2.1 安装依赖2.2 解压包2.3 编译并安装2.4 指定配置启动2.5 设置redis开机自启 一&#xff0c;redis下载 官网&#xff1a; https://redis.io1.1上传到linux服务器上 我用filezila上传到/us…

使用PHPStudy搭建本地web网站并实现任意浏览器公网访问

文章目录 [toc]使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2…

失物招领|基于Springboot的校园失物招领系统设计与实现(源码+数据库+文档)

校园失物招领系统目录 目录 基于Springboot的校园失物招领系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、 管理员功能实现 (1) 失物招领管理 (2) 寻物启事管理 (3) 公告管理 (4) 公告类型管理 2、用户功能实现 (1) 失物招领 (2) 寻物启事 (3) 公告 …

服务器性能监控管理方法及工具

服务器是组织数据中心的主干&#xff0c;无论是优化的用户体验&#xff0c;还是管理良好的资源&#xff0c;服务器都能为您完成所有工作&#xff0c;保持服务器随时可用和可访问对于面向业务的应用程序和服务以最佳水平运行至关重要。 理想的服务器性能需要主动监控物理和虚拟…

SpringMVC处理ajax请求之@ResponseBody注解,将后端数据响应到浏览器

上一篇文章讲到SpringMVC处理ajax请求用到的RequestBody注解SpringMVC处理ajax请求&#xff08;RequestBody注解&#xff09;&#xff0c;ajax向后端传递的数据格式详解-CSDN博客&#xff0c;这个注解帮我们解决了如何将客户端的数据通过json数据传递到服务器&#xff0c;简单说…

Mybatis Plus 插件失效问题记录

Mybatis Plus 插件失效问题记录 1. 问题发生场景2.问题发生原理与解决方法 1. 问题发生场景 在配置了Mybatis Plus分页查询后&#xff0c;自定义拦截器&#xff08;插件&#xff09;失效。 SpringBootApplication public class MybatisPlusDemoApplication {public static vo…

Python实现PDF到HTML的转换

PDF文件是共享和分发文档的常用选择&#xff0c;但提取和再利用PDF文件中的内容可能会非常麻烦。而利用Python将PDF文件转换为HTML是解决此问题的理想方案之一&#xff0c;这样做可以增强文档可访问性&#xff0c;使文档可搜索&#xff0c;同时增强文档在不同场景中的实用性。此…

MQ面试题整理(持续更新)

1. MQ的优缺点 优点&#xff1a;解耦&#xff0c;异步&#xff0c;削峰 缺点&#xff1a; 系统可用性降低 系统引入的外部依赖越多&#xff0c;越容易挂掉。万一 MQ 挂了&#xff0c;MQ 一挂&#xff0c;整套系统崩 溃&#xff0c;你不就完了&#xff1f;系统复杂度提高 硬生…

微服务入门篇:Nacos注册中心(Nacos安装,快速入门,多级存储,负载均衡,环境隔离,配置管理,热更新,集群搭建,nginx反向代理)

目录 1.Nacos安装1.官网下载2.解压到本地3.启动nacos 2.Nacos快速入门1.在父工程中导入nacos依赖2.给子项目添加客户端依赖3.修改对应服务的配置文件4.启动服务&#xff0c;查看nacos发现情况 3.Nacos服务多级存储模型4.NacosRule负载均衡5. 服务实例的权重设置6.环境隔离&…

Pytest 与allure测试报告集成

通过Feature, story, step 记录测试的功能&#xff0c;场景及测试步骤 # login.pylogin_func函数 传入参数是name 和 password 当输入的name和password与数据库db_data中数据一致时&#xff0c;返回“XXX成功登录系统&#xff01;” 当输入的name存在于数据库db_data但密码不正…