PalletTool.cs 13 KB

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