PalletTool.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using MathNet.Numerics.LinearAlgebra;
  2. using NPOI.SS.Formula.Functions;
  3. using OpenCvSharp;
  4. using OpenCvSharp.Flann;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Data.Common;
  8. using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Controls;
  14. using TeamAAS_VP.Models;
  15. using TeamAAS_VP.Models.Robot;
  16. using Unity;
  17. namespace TeamAAS_VP.Core
  18. {
  19. public class PalletTool
  20. {
  21. private List<List<RPoint>> rPoints=new List<List<RPoint>>();
  22. public RPoint[] Points { get; set; }
  23. Pallet pallet;
  24. public PalletTool(Pallet pallet1)
  25. {
  26. pallet= pallet1;
  27. //----------------------------------------计算旋转矩阵-----------------------------------------------------------------
  28. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { pallet.P0.X, pallet.P0.Y });
  29. Vector<double> p2 = Vector<double>.Build.Dense(new double[] { pallet.P1.X, pallet.P1.Y });
  30. Vector<double> p3 = Vector<double>.Build.Dense(new double[] { pallet.P2.X, pallet.P2.Y });
  31. //计算正交时的X与Y轴的单位向量
  32. Vector<double> E1 = (p2 - p1) / (p2 - p1).L2Norm();
  33. Vector<double> E2 = (p3 - p1 - E1.DotProduct(p3 - p1) * E1) / (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm();
  34. //得到旋转矩阵
  35. Matrix<double> R= Matrix<double>.Build.DenseOfColumnVectors(E1, E2);
  36. //--------------------------------------计算切变矩阵--------------------------------------------------------
  37. double a = (E1.DotProduct(p3 - p1) * E1).L2Norm() / (p3 - p1-(E1.DotProduct(p3 - p1) * E1))[1];
  38. Matrix<double> Shear = Matrix<double>.Build.DenseOfArray(new double[,] { {1,a },{0,1 } });
  39. //--------------------------------------计算托盘行列间距---------------------------------------------------------
  40. double distanceX = (p2 - p1).L2Norm() / (pallet.Column-1);
  41. double distanceY = (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm() / (pallet.Row-1);
  42. //------------------------------------生成切变前的行列坐标集合-------------------------------------------------------
  43. List<double> cols = new List<double>();
  44. for (int i = 0; i < pallet.Column; i++)
  45. {
  46. cols.Add(distanceX*i);
  47. }
  48. List<double> rows = new List<double>();
  49. for (int i = 0; i < pallet.Row; i++)
  50. {
  51. rows.Add(distanceY * i);
  52. }
  53. //-------------------------------------计算转换后的机器人绝对坐标系下的所有托盘点---------------------------------------
  54. rPoints.Clear();
  55. for (int i = 0;i<rows.Count; i++)
  56. {
  57. rPoints.Add(new List<RPoint>());
  58. for (int j = 0;j<cols.Count; j++)
  59. {
  60. //切变前的坐标
  61. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  62. //切变后的坐标
  63. Vector<double> h = Shear * q;
  64. //转换后的机器人坐标
  65. Vector<double> rp = R * h + p1;
  66. //输出完整的机器人坐标
  67. rPoints[rPoints.Count-1].Add(new RPoint() { X = (float)rp[0], Y = (float)rp[1], Z = pallet.P0.Z, U = pallet.P0.U, V = pallet.P0.V, W = pallet.P0.W, Hand = pallet.P0.Hand, Local = pallet.P0.Local, Tool = pallet.P0.Tool });
  68. }
  69. }
  70. //-----------------------------------------------排序---------------------------------------------------------------
  71. List<RPoint> newPoints= new List<RPoint>();
  72. if (pallet.Arrangement== Enums.PalletArrangement.Z)
  73. {
  74. foreach (var item in rPoints)
  75. {
  76. foreach (var item1 in item)
  77. {
  78. newPoints.Add(item1);
  79. }
  80. }
  81. Points = newPoints.ToArray();
  82. }
  83. else
  84. {
  85. for (int i = 0; i < rows.Count; i++)
  86. {
  87. if (i % 2 == 0) //偶数
  88. {
  89. for (int j = 0; j < cols.Count; j++)
  90. {
  91. newPoints.Add(rPoints[i][j]);
  92. }
  93. }
  94. else
  95. {
  96. for (int j = cols.Count - 1; j > -1; j--)
  97. {
  98. newPoints.Add(rPoints[i][j]);
  99. }
  100. }
  101. }
  102. Points = newPoints.ToArray();
  103. }
  104. //组合托盘
  105. if (pallet.Extend!=null)
  106. {
  107. //-------------------------------------计算转换后的用户坐标系中的机器人点位---------------------------------------
  108. rPoints.Clear();
  109. for (int i = 0; i < rows.Count; i++)
  110. {
  111. rPoints.Add(new List<RPoint>());
  112. for (int j = 0; j < cols.Count; j++)
  113. {
  114. //切变前的坐标
  115. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  116. //切变后的坐标
  117. Vector<double> h = Shear * q;
  118. //未转换前的托盘点
  119. rPoints[rPoints.Count - 1].Add(new RPoint() { X = (float)h[0], Y = (float)h[1], Z = pallet.P0.Z, U = pallet.P0.U, V = pallet.P0.V, W = pallet.P0.W, Hand = pallet.P0.Hand, Local = pallet.P0.Local, Tool = pallet.P0.Tool });
  120. }
  121. }
  122. //-----------------------------------------------排序---------------------------------------------------------------
  123. newPoints.Clear();
  124. if (pallet.Arrangement == Enums.PalletArrangement.Z)
  125. {
  126. foreach (var item in rPoints)
  127. {
  128. foreach (var item1 in item)
  129. {
  130. newPoints.Add(item1);
  131. }
  132. }
  133. }
  134. else
  135. {
  136. for (int i = 0; i < rows.Count; i++)
  137. {
  138. if (i % 2 == 0) //偶数
  139. {
  140. for (int j = 0; j < cols.Count; j++)
  141. {
  142. newPoints.Add(rPoints[i][j]);
  143. }
  144. }
  145. else
  146. {
  147. for (int j = cols.Count - 1; j > -1; j--)
  148. {
  149. newPoints.Add(rPoints[i][j]);
  150. }
  151. }
  152. }
  153. }
  154. //一个大托盘中,包含每个托盘的点位(大托盘<一行托盘>-<一行托盘中所有列托盘>-<一个托盘中所有的点位>)
  155. List<List<List<RPoint>>> nPoints = new List<List<List<RPoint>>>();
  156. //遍历所有的行
  157. for (int i = 0;i < pallet.Extend.Pallet_Row; i++)
  158. {
  159. nPoints.Add(new List<List<RPoint>>());
  160. //遍历每行中所有列
  161. for (int j = 0; j < pallet.Extend.Pallet_Column; j++)
  162. {
  163. nPoints[nPoints.Count-1].Add(new List<RPoint>());
  164. double dx = pallet.Extend.Pallet_X_Interval * i;
  165. double dy = pallet.Extend.Pallet_Y_Interval * j;
  166. //如果是切变矩阵模式
  167. if (pallet.Extend.CoordinateModel== Enums.CoordinateModel.Shear)
  168. {
  169. //切变前的坐标
  170. Vector<double> q = Vector<double>.Build.Dense(new double[] { 0, dx });
  171. //切变后的坐标
  172. Vector<double> h = Shear * q;
  173. dy += h[0];
  174. dx = h[1];
  175. }
  176. foreach (var item in newPoints)
  177. {
  178. //偏移的向量
  179. Vector<double> q = Vector<double>.Build.Dense(new double[] { dy, dx });
  180. Vector<double> q1 = Vector<double>.Build.Dense(new double[] { item.X, item.Y });
  181. Vector<double> rp = R * (q + q1) + p1;
  182. nPoints[nPoints.Count - 1][nPoints[nPoints.Count - 1].Count-1].Add(new RPoint() { X = (float)rp[0], Y = (float)rp[1], Z = item.Z, U = item.U, V = item.V, W = item.W, Hand = item.Hand, Local = item.Local, Tool = item.Tool });
  183. }
  184. }
  185. }
  186. newPoints = new List<RPoint>();
  187. //对组合的所有托盘排序
  188. if (pallet.Arrangement == Enums.PalletArrangement.Z)
  189. {
  190. foreach (var item in nPoints)
  191. {
  192. foreach (var item1 in item)
  193. {
  194. foreach (var item2 in item1)
  195. {
  196. newPoints.Add(item2);
  197. }
  198. }
  199. }
  200. Points = newPoints.ToArray();
  201. }
  202. else
  203. {
  204. for (int i = 0; i < nPoints.Count; i++)
  205. {
  206. if (i % 2 == 0) //偶数
  207. {
  208. for (int j = 0; j < nPoints[i].Count; j++)
  209. {
  210. foreach (var item2 in nPoints[i][j])
  211. {
  212. newPoints.Add(item2);
  213. }
  214. }
  215. }
  216. else
  217. {
  218. for (int j = nPoints[i].Count - 1; j > -1; j--)
  219. {
  220. foreach (var item2 in nPoints[i][j])
  221. {
  222. newPoints.Add(item2);
  223. }
  224. }
  225. }
  226. }
  227. Points = newPoints.ToArray();
  228. }
  229. }
  230. }
  231. /// <summary>
  232. /// 绘制
  233. /// </summary>
  234. /// <param name="filePath"></param>
  235. public void DrawCoordinatesAndSaveImage(string filePath)
  236. {
  237. string flo = Path.GetExtension(filePath);
  238. string pa = filePath.Replace(flo,".csv");
  239. StreamWriter writer = new StreamWriter(pa);
  240. foreach (var item in Points)
  241. {
  242. writer.WriteLine($"{item.X},{item.Y}");
  243. }
  244. writer.Close();
  245. writer.Dispose();
  246. int width = 800;
  247. int height = 600;
  248. //X方向 点位 最小值
  249. double minx= Points.Min(p => p.X);
  250. //X方向 点位 最大值
  251. double maxx = Points.Max(p => p.X);
  252. //Y方向 点位 最小值
  253. double miny = Points.Max(p => p.Y);
  254. //Y方向 点位 最小值
  255. double maxy = Points.Max(p => p.Y);
  256. double xoffset = minx <0? Math.Abs(minx)+10 :10;
  257. double yoffset = miny < 0 ? Math.Abs(miny)+10 : 10;
  258. double xZoom = minx < 0? width / (maxx - minx): width / maxx;
  259. double yZoom = miny < 0 ? height / (maxy - miny) : height / maxy;
  260. // 创建一个空白图像
  261. Mat image = new Mat(height+50, width+50,MatType.CV_8UC3); // 3通道(BGR),8位深度
  262. image.SetTo(new Scalar(255, 255, 255)); // 设置为白色背景
  263. // 绘制十字叉
  264. foreach (var point in Points)
  265. {
  266. OpenCvSharp.Point point1=new Point(point.X* xZoom+ xoffset, point.Y * yZoom + yoffset);
  267. Cv2.DrawMarker(image, point1, Scalar.Blue,MarkerTypes.Cross,20,2); // 红色十字叉
  268. }
  269. // 定义坐标系的原点
  270. Point origin = new Point(xoffset, yoffset);
  271. // 画 X 轴
  272. Cv2.Line(image, new Point(0, origin.Y), new Point(width, origin.Y), Scalar.Green, 2);
  273. Cv2.PutText(image, "X", new Point(width - 20, origin.Y + 10), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
  274. // 画 Y 轴
  275. Cv2.Line(image, new Point(origin.X, 0), new Point(origin.X, height), Scalar.Red, 2);
  276. Cv2.PutText(image, "Y", new Point(origin.X + 10, height-20), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
  277. Cv2.Flip(image, image,FlipMode.X);
  278. // 保存图像
  279. Cv2.ImWrite(filePath, image);
  280. image.Dispose();
  281. }
  282. }
  283. }