PalletTool.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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.PLC;
  16. using TeamAAS_VP.Models.Robot;
  17. using Unity;
  18. namespace TeamAAS_VP.Core
  19. {
  20. public class PalletTool
  21. {
  22. private List<List<RPoint>> rPoints=new List<List<RPoint>>();
  23. private List<List<PlcPoint>> plcPoints = new List<List<PlcPoint>>();
  24. public RPoint[] Points { get; set; }
  25. public PlcPoint[] PlcPoints { get; set; }
  26. Pallet pallet;
  27. PalletEx _pallet1;
  28. public PalletTool(Pallet pallet1)
  29. {
  30. pallet= pallet1;
  31. //----------------------------------------计算旋转矩阵-----------------------------------------------------------------
  32. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { pallet.P0.X, pallet.P0.Y });
  33. Vector<double> p2 = Vector<double>.Build.Dense(new double[] { pallet.P1.X, pallet.P1.Y });
  34. Vector<double> p3 = Vector<double>.Build.Dense(new double[] { pallet.P2.X, pallet.P2.Y });
  35. //计算正交时的X与Y轴的单位向量
  36. Vector<double> E1 = (p2 - p1) / (p2 - p1).L2Norm();
  37. Vector<double> E2 = (p3 - p1 - E1.DotProduct(p3 - p1) * E1) / (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm();
  38. //得到旋转矩阵
  39. Matrix<double> R= Matrix<double>.Build.DenseOfColumnVectors(E1, E2);
  40. //--------------------------------------计算切变矩阵--------------------------------------------------------
  41. double a = (E1.DotProduct(p3 - p1) * E1).L2Norm() / (p3 - p1-(E1.DotProduct(p3 - p1) * E1))[1];
  42. Matrix<double> Shear = Matrix<double>.Build.DenseOfArray(new double[,] { {1,a },{0,1 } });
  43. //--------------------------------------计算托盘行列间距---------------------------------------------------------
  44. double distanceX = (p2 - p1).L2Norm() / (pallet.Column-1);
  45. double distanceY = (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm() / (pallet.Row-1);
  46. //------------------------------------生成切变前的行列坐标集合-------------------------------------------------------
  47. List<double> cols = new List<double>();
  48. for (int i = 0; i < pallet.Column; i++)
  49. {
  50. cols.Add(distanceX*i);
  51. }
  52. List<double> rows = new List<double>();
  53. for (int i = 0; i < pallet.Row; i++)
  54. {
  55. rows.Add(distanceY * i);
  56. }
  57. //-------------------------------------计算转换后的机器人绝对坐标系下的所有托盘点---------------------------------------
  58. rPoints.Clear();
  59. for (int i = 0;i<rows.Count; i++)
  60. {
  61. rPoints.Add(new List<RPoint>());
  62. for (int j = 0;j<cols.Count; j++)
  63. {
  64. //切变前的坐标
  65. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  66. //切变后的坐标
  67. Vector<double> h = Shear * q;
  68. //转换后的机器人坐标
  69. Vector<double> rp = R * h + p1;
  70. //输出完整的机器人坐标
  71. 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 });
  72. }
  73. }
  74. //-----------------------------------------------排序---------------------------------------------------------------
  75. List<RPoint> newPoints= new List<RPoint>();
  76. if (pallet.Arrangement== Enums.PalletArrangement.Z)
  77. {
  78. foreach (var item in rPoints)
  79. {
  80. foreach (var item1 in item)
  81. {
  82. newPoints.Add(item1);
  83. }
  84. }
  85. Points = newPoints.ToArray();
  86. }
  87. else
  88. {
  89. for (int i = 0; i < rows.Count; i++)
  90. {
  91. if (i % 2 == 0) //偶数
  92. {
  93. for (int j = 0; j < cols.Count; j++)
  94. {
  95. newPoints.Add(rPoints[i][j]);
  96. }
  97. }
  98. else
  99. {
  100. for (int j = cols.Count - 1; j > -1; j--)
  101. {
  102. newPoints.Add(rPoints[i][j]);
  103. }
  104. }
  105. }
  106. Points = newPoints.ToArray();
  107. }
  108. //组合托盘
  109. if (pallet.Extend!=null)
  110. {
  111. //-------------------------------------计算转换后的用户坐标系中的机器人点位---------------------------------------
  112. rPoints.Clear();
  113. for (int i = 0; i < rows.Count; i++)
  114. {
  115. rPoints.Add(new List<RPoint>());
  116. for (int j = 0; j < cols.Count; j++)
  117. {
  118. //切变前的坐标
  119. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  120. //切变后的坐标
  121. Vector<double> h = Shear * q;
  122. //未转换前的托盘点
  123. 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 });
  124. }
  125. }
  126. //-----------------------------------------------排序---------------------------------------------------------------
  127. newPoints.Clear();
  128. if (pallet.Arrangement == Enums.PalletArrangement.Z)
  129. {
  130. foreach (var item in rPoints)
  131. {
  132. foreach (var item1 in item)
  133. {
  134. newPoints.Add(item1);
  135. }
  136. }
  137. }
  138. else
  139. {
  140. for (int i = 0; i < rows.Count; i++)
  141. {
  142. if (i % 2 == 0) //偶数
  143. {
  144. for (int j = 0; j < cols.Count; j++)
  145. {
  146. newPoints.Add(rPoints[i][j]);
  147. }
  148. }
  149. else
  150. {
  151. for (int j = cols.Count - 1; j > -1; j--)
  152. {
  153. newPoints.Add(rPoints[i][j]);
  154. }
  155. }
  156. }
  157. }
  158. //一个大托盘中,包含每个托盘的点位(大托盘<一行托盘>-<一行托盘中所有列托盘>-<一个托盘中所有的点位>)
  159. List<List<List<RPoint>>> nPoints = new List<List<List<RPoint>>>();
  160. //遍历所有的行
  161. for (int i = 0;i < pallet.Extend.Pallet_Row; i++)
  162. {
  163. nPoints.Add(new List<List<RPoint>>());
  164. //遍历每行中所有列
  165. for (int j = 0; j < pallet.Extend.Pallet_Column; j++)
  166. {
  167. nPoints[nPoints.Count-1].Add(new List<RPoint>());
  168. double dx = pallet.Extend.Pallet_X_Interval * i;
  169. double dy = pallet.Extend.Pallet_Y_Interval * j;
  170. //如果是切变矩阵模式
  171. if (pallet.Extend.CoordinateModel== Enums.CoordinateModel.Shear)
  172. {
  173. //切变前的坐标
  174. Vector<double> q = Vector<double>.Build.Dense(new double[] { 0, dx });
  175. //切变后的坐标
  176. Vector<double> h = Shear * q;
  177. dy += h[0];
  178. dx = h[1];
  179. }
  180. foreach (var item in newPoints)
  181. {
  182. //偏移的向量
  183. Vector<double> q = Vector<double>.Build.Dense(new double[] { dy, dx });
  184. Vector<double> q1 = Vector<double>.Build.Dense(new double[] { item.X, item.Y });
  185. Vector<double> rp = R * (q + q1) + p1;
  186. 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 });
  187. }
  188. }
  189. }
  190. newPoints = new List<RPoint>();
  191. //对组合的所有托盘排序
  192. if (pallet.Arrangement == Enums.PalletArrangement.Z)
  193. {
  194. foreach (var item in nPoints)
  195. {
  196. foreach (var item1 in item)
  197. {
  198. foreach (var item2 in item1)
  199. {
  200. newPoints.Add(item2);
  201. }
  202. }
  203. }
  204. Points = newPoints.ToArray();
  205. }
  206. else
  207. {
  208. for (int i = 0; i < nPoints.Count; i++)
  209. {
  210. if (i % 2 == 0) //偶数
  211. {
  212. for (int j = 0; j < nPoints[i].Count; j++)
  213. {
  214. foreach (var item2 in nPoints[i][j])
  215. {
  216. newPoints.Add(item2);
  217. }
  218. }
  219. }
  220. else
  221. {
  222. for (int j = nPoints[i].Count - 1; j > -1; j--)
  223. {
  224. foreach (var item2 in nPoints[i][j])
  225. {
  226. newPoints.Add(item2);
  227. }
  228. }
  229. }
  230. }
  231. Points = newPoints.ToArray();
  232. }
  233. }
  234. }
  235. public PalletTool(PalletEx pallet1)
  236. {
  237. _pallet1 = pallet1;
  238. //----------------------------------------计算旋转矩阵-----------------------------------------------------------------
  239. Vector<double> p1 = Vector<double>.Build.Dense(new double[] { _pallet1.P0.X_Position, _pallet1.P0.Y_Position });
  240. Vector<double> p2 = Vector<double>.Build.Dense(new double[] { _pallet1.P1.X_Position, _pallet1.P1.Y_Position });
  241. Vector<double> p3 = Vector<double>.Build.Dense(new double[] { _pallet1.P2.X_Position, _pallet1.P2.Y_Position });
  242. //计算正交时的X与Y轴的单位向量
  243. Vector<double> E1 = (p2 - p1) / (p2 - p1).L2Norm();
  244. Vector<double> E2 = (p3 - p1 - E1.DotProduct(p3 - p1) * E1) / (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm();
  245. //得到旋转矩阵
  246. Matrix<double> R = Matrix<double>.Build.DenseOfColumnVectors(E1, E2);
  247. //--------------------------------------计算切变矩阵--------------------------------------------------------
  248. double a = (E1.DotProduct(p3 - p1) * E1).L2Norm() / (p3 - p1 - (E1.DotProduct(p3 - p1) * E1))[1];
  249. Matrix<double> Shear = Matrix<double>.Build.DenseOfArray(new double[,] { { 1, a }, { 0, 1 } });
  250. //--------------------------------------计算托盘行列间距---------------------------------------------------------
  251. double distanceX = (p2 - p1).L2Norm() / (_pallet1.Column - 1);
  252. double distanceY = (p3 - p1 - E1.DotProduct(p3 - p1) * E1).L2Norm() / (_pallet1.Row - 1);
  253. //------------------------------------生成切变前的行列坐标集合-------------------------------------------------------
  254. List<double> cols = new List<double>();
  255. for (int i = 0; i < _pallet1.Column; i++)
  256. {
  257. cols.Add(distanceX * i);
  258. }
  259. List<double> rows = new List<double>();
  260. for (int i = 0; i < _pallet1.Row; i++)
  261. {
  262. rows.Add(distanceY * i);
  263. }
  264. //-------------------------------------计算转换后的机器人绝对坐标系下的所有托盘点---------------------------------------
  265. plcPoints.Clear();
  266. for (int i = 0; i < rows.Count; i++)
  267. {
  268. plcPoints.Add(new List<PlcPoint>());
  269. for (int j = 0; j < cols.Count; j++)
  270. {
  271. //切变前的坐标
  272. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  273. //切变后的坐标
  274. Vector<double> h = Shear * q;
  275. //转换后的机器人坐标
  276. Vector<double> rp = R * h + p1;
  277. //输出完整的机器人坐标
  278. plcPoints[plcPoints.Count - 1].Add(new PlcPoint() { X_Position = (float)rp[0], Y_Position = (float)rp[1], Z_Position_Start = _pallet1.P0.Z_Position_Start,Z_Position_Stop= _pallet1.P0.Z_Position_Stop, U_Position = _pallet1.P0.U_Position});
  279. }
  280. }
  281. //-----------------------------------------------排序---------------------------------------------------------------
  282. List<PlcPoint> newPoints = new List<PlcPoint>();
  283. if (_pallet1.Arrangement == Enums.PalletArrangement.Z)
  284. {
  285. foreach (var item in plcPoints)
  286. {
  287. foreach (var item1 in item)
  288. {
  289. newPoints.Add(item1);
  290. }
  291. }
  292. PlcPoints = newPoints.ToArray();
  293. }
  294. else
  295. {
  296. for (int i = 0; i < rows.Count; i++)
  297. {
  298. if (i % 2 == 0) //偶数
  299. {
  300. for (int j = 0; j < cols.Count; j++)
  301. {
  302. newPoints.Add(plcPoints[i][j]);
  303. }
  304. }
  305. else
  306. {
  307. for (int j = cols.Count - 1; j > -1; j--)
  308. {
  309. newPoints.Add(plcPoints[i][j]);
  310. }
  311. }
  312. }
  313. PlcPoints = newPoints.ToArray();
  314. }
  315. //组合托盘
  316. if (_pallet1.Extend != null)
  317. {
  318. //-------------------------------------计算转换后的用户坐标系中的机器人点位---------------------------------------
  319. plcPoints.Clear();
  320. for (int i = 0; i < rows.Count; i++)
  321. {
  322. plcPoints.Add(new List<PlcPoint>());
  323. for (int j = 0; j < cols.Count; j++)
  324. {
  325. //切变前的坐标
  326. Vector<double> q = Vector<double>.Build.Dense(new double[] { cols[j], rows[i] });
  327. //切变后的坐标
  328. Vector<double> h = Shear * q;
  329. //未转换前的托盘点
  330. plcPoints[plcPoints.Count - 1].Add(new PlcPoint() { X_Position = (float)h[0], Y_Position = (float)h[1], Z_Position_Start = _pallet1.P0.Z_Position_Start,Z_Position_Stop= pallet1.P0.Z_Position_Stop, U_Position = _pallet1.P0.U_Position});
  331. }
  332. }
  333. //-----------------------------------------------排序---------------------------------------------------------------
  334. newPoints.Clear();
  335. if (_pallet1.Arrangement == Enums.PalletArrangement.Z)
  336. {
  337. foreach (var item in plcPoints)
  338. {
  339. foreach (var item1 in item)
  340. {
  341. newPoints.Add(item1);
  342. }
  343. }
  344. }
  345. else
  346. {
  347. for (int i = 0; i < rows.Count; i++)
  348. {
  349. if (i % 2 == 0) //偶数
  350. {
  351. for (int j = 0; j < cols.Count; j++)
  352. {
  353. newPoints.Add(plcPoints[i][j]);
  354. }
  355. }
  356. else
  357. {
  358. for (int j = cols.Count - 1; j > -1; j--)
  359. {
  360. newPoints.Add(plcPoints[i][j]);
  361. }
  362. }
  363. }
  364. }
  365. //一个大托盘中,包含每个托盘的点位(大托盘<一行托盘>-<一行托盘中所有列托盘>-<一个托盘中所有的点位>)
  366. List<List<List<PlcPoint>>> nPoints = new List<List<List<PlcPoint>>>();
  367. //遍历所有的行
  368. for (int i = 0; i < _pallet1.Extend.Pallet_Row; i++)
  369. {
  370. nPoints.Add(new List<List<PlcPoint>>());
  371. //遍历每行中所有列
  372. for (int j = 0; j < _pallet1.Extend.Pallet_Column; j++)
  373. {
  374. nPoints[nPoints.Count - 1].Add(new List<PlcPoint>());
  375. double dx = _pallet1.Extend.Pallet_X_Interval * i;
  376. double dy = _pallet1.Extend.Pallet_Y_Interval * j;
  377. //如果是切变矩阵模式
  378. if (_pallet1.Extend.CoordinateModel == Enums.CoordinateModel.Shear)
  379. {
  380. //切变前的坐标
  381. Vector<double> q = Vector<double>.Build.Dense(new double[] { 0, dx });
  382. //切变后的坐标
  383. Vector<double> h = Shear * q;
  384. dy += h[0];
  385. dx = h[1];
  386. }
  387. foreach (var item in newPoints)
  388. {
  389. //偏移的向量
  390. Vector<double> q = Vector<double>.Build.Dense(new double[] { dy, dx });
  391. Vector<double> q1 = Vector<double>.Build.Dense(new double[] { item.X_Position, item.Y_Position });
  392. Vector<double> rp = R * (q + q1) + p1;
  393. nPoints[nPoints.Count - 1][nPoints[nPoints.Count - 1].Count - 1].Add(new PlcPoint() { X_Position = (float)rp[0], Y_Position = (float)rp[1], Z_Position_Start = item.Z_Position_Start,Z_Position_Stop=item.Z_Position_Stop, U_Position = item.U_Position});
  394. }
  395. }
  396. }
  397. newPoints = new List<PlcPoint>();
  398. //对组合的所有托盘排序
  399. if (_pallet1.Arrangement == Enums.PalletArrangement.Z)
  400. {
  401. foreach (var item in nPoints)
  402. {
  403. foreach (var item1 in item)
  404. {
  405. foreach (var item2 in item1)
  406. {
  407. newPoints.Add(item2);
  408. }
  409. }
  410. }
  411. PlcPoints = newPoints.ToArray();
  412. }
  413. else
  414. {
  415. for (int i = 0; i < nPoints.Count; i++)
  416. {
  417. if (i % 2 == 0) //偶数
  418. {
  419. for (int j = 0; j < nPoints[i].Count; j++)
  420. {
  421. foreach (var item2 in nPoints[i][j])
  422. {
  423. newPoints.Add(item2);
  424. }
  425. }
  426. }
  427. else
  428. {
  429. for (int j = nPoints[i].Count - 1; j > -1; j--)
  430. {
  431. foreach (var item2 in nPoints[i][j])
  432. {
  433. newPoints.Add(item2);
  434. }
  435. }
  436. }
  437. }
  438. PlcPoints = newPoints.ToArray();
  439. }
  440. }
  441. }
  442. /// <summary>
  443. /// 绘制
  444. /// </summary>
  445. /// <param name="filePath"></param>
  446. public void DrawCoordinatesAndSaveImage(string filePath)
  447. {
  448. string flo = Path.GetExtension(filePath);
  449. string pa = filePath.Replace(flo,".csv");
  450. StreamWriter writer = new StreamWriter(pa);
  451. foreach (var item in Points)
  452. {
  453. writer.WriteLine($"{item.X},{item.Y}");
  454. }
  455. writer.Close();
  456. writer.Dispose();
  457. int width = 800;
  458. int height = 600;
  459. //X方向 点位 最小值
  460. double minx= Points.Min(p => p.X);
  461. //X方向 点位 最大值
  462. double maxx = Points.Max(p => p.X);
  463. //Y方向 点位 最小值
  464. double miny = Points.Max(p => p.Y);
  465. //Y方向 点位 最小值
  466. double maxy = Points.Max(p => p.Y);
  467. double xoffset = minx <0? Math.Abs(minx)+10 :10;
  468. double yoffset = miny < 0 ? Math.Abs(miny)+10 : 10;
  469. double xZoom = minx < 0? width / (maxx - minx): width / maxx;
  470. double yZoom = miny < 0 ? height / (maxy - miny) : height / maxy;
  471. // 创建一个空白图像
  472. Mat image = new Mat(height+50, width+50,MatType.CV_8UC3); // 3通道(BGR),8位深度
  473. image.SetTo(new Scalar(255, 255, 255)); // 设置为白色背景
  474. // 绘制十字叉
  475. foreach (var point in Points)
  476. {
  477. OpenCvSharp.Point point1=new Point(point.X* xZoom+ xoffset, point.Y * yZoom + yoffset);
  478. Cv2.DrawMarker(image, point1, Scalar.Blue,MarkerTypes.Cross,20,2); // 红色十字叉
  479. }
  480. // 定义坐标系的原点
  481. Point origin = new Point(xoffset, yoffset);
  482. // 画 X 轴
  483. Cv2.Line(image, new Point(0, origin.Y), new Point(width, origin.Y), Scalar.Green, 2);
  484. Cv2.PutText(image, "X", new Point(width - 20, origin.Y + 10), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
  485. // 画 Y 轴
  486. Cv2.Line(image, new Point(origin.X, 0), new Point(origin.X, height), Scalar.Red, 2);
  487. Cv2.PutText(image, "Y", new Point(origin.X + 10, height-20), HersheyFonts.HersheySimplex, 1, Scalar.Blue, 2);
  488. Cv2.Flip(image, image,FlipMode.X);
  489. // 保存图像
  490. Cv2.ImWrite(filePath, image);
  491. image.Dispose();
  492. }
  493. }
  494. }