MathTools3D.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Runtime.Serialization;
  6. using AI.Common;
  7. using AI.Common.Log;
  8. using AI.Common.Tools;
  9. namespace AI.Reconstruction
  10. {
  11. /// <summary>
  12. /// 计算切面的三个点, 3维点坐标
  13. /// </summary>
  14. public struct One2DPlaneThreeBasic3DPoints
  15. {
  16. public Point3DF ZeroPoint;
  17. public Point3DF XAxisPoint;
  18. public Point3DF YAxisPoint;
  19. }
  20. /// <summary>
  21. /// 计算切面的三个点, 2维点坐标
  22. /// </summary>
  23. public struct One2DPlaneThreeBasic2DPoints
  24. {
  25. public Point2D ZeroPoint;
  26. public Point2D XAxisPoint;
  27. public Point2D YAxisPoint;
  28. }
  29. /// <summary>
  30. /// 计算切面的三个点
  31. /// </summary>
  32. public struct One3DPlaneThreeBasicPoints
  33. {
  34. public Point3DF PointA;
  35. public Point3DF PointB;
  36. public Point3DF PointC;
  37. }
  38. /// <summary>
  39. /// 平面方程Ax+By+CZ+D=0;
  40. /// </summary>
  41. public struct PlaneEquation
  42. {
  43. public double A;
  44. public double B;
  45. public double C;
  46. public double D;
  47. }
  48. /// <summary>
  49. /// 三维空间线段
  50. /// </summary>
  51. public struct LineSegment3I
  52. {
  53. //线段开始的端点
  54. public Point3D EndPointBegin;
  55. //线段结束的端点
  56. public Point3D EndPointEnd;
  57. }
  58. /// <summary>
  59. /// 三维坐标变换
  60. /// </summary>
  61. public struct CoordinateTransformation3D
  62. {
  63. public double[] RotationMatrix;
  64. public double[] TranslationMatrix;
  65. }
  66. /// <summary>
  67. /// 切片端点的世界点和图像点,cosA是图像点向量与图像X轴的夹角余弦值
  68. /// </summary>
  69. public struct EndPointStruct
  70. {
  71. public Point3DF EndPoint3D;
  72. public Point2D EndPoint2I;
  73. public double CosA;
  74. //分子
  75. public long Molecule;
  76. //分母
  77. public long Denominator;
  78. }
  79. public class MathTools3D
  80. {
  81. //精度要求
  82. public static float Precision = 0.0001f;
  83. //精度要求
  84. public static float NegPrecision = -0.0001f;
  85. public static bool TwoDoubleEqual(double d1, double d2)
  86. {
  87. return Math.Abs(d1 - d2) < Precision;
  88. }
  89. /// <summary>
  90. /// 根据三个点计算平面方程
  91. /// </summary>
  92. /// <param name="point1"></param>
  93. /// <param name="point2"></param>
  94. /// <param name="point3"></param>
  95. /// <returns></returns>
  96. public static PlaneEquation GetPlaneEquation(Point3DF point1, Point3DF point2, Point3DF point3)
  97. {
  98. try
  99. {
  100. if (IsParallel(point1, point2, point3))
  101. {
  102. LogHelper.ErrorLog("MathTools3D GetPlaneEquation, three points is in one line.");
  103. return new PlaneEquation { A = 0, B = 0, C = 0, D = 0 };
  104. }
  105. var x1 = point1.X;
  106. var y1 = point1.Y;
  107. var z1 = point1.Z;
  108. var x2 = point2.X;
  109. var y2 = point2.Y;
  110. var z2 = point2.Z;
  111. var x3 = point3.X;
  112. var y3 = point3.Y;
  113. var z3 = point3.Z;
  114. //平面方程Ax+By+CZ+D=0;
  115. var a = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2);
  116. var b = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2);
  117. var c = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2);
  118. var d = -x1 * (y2 * z3 - y3 * z2) - x2 * (y3 * z1 - y1 * z3) - x3 * (y1 * z2 - y2 * z1);
  119. return new PlaneEquation { A = a, B = b, C = c, D = d };
  120. }
  121. catch (Exception e)
  122. {
  123. LogHelper.ErrorLog("MathTools3D GetPlaneEquation error," + e.Message + "," + e.StackTrace);
  124. return new PlaneEquation { A = 0, B = 0, C = 0, D = 0 };
  125. }
  126. }
  127. /// <summary>
  128. /// 判断三个点是否共线
  129. /// </summary>
  130. /// <param name="p1"></param>
  131. /// <param name="p2"></param>
  132. /// <param name="p3"></param>
  133. /// <returns></returns>
  134. public static bool IsParallel(Point3D p1, Point3D p2, Point3D p3)
  135. {
  136. var v1 = new Point3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
  137. var v2 = new Point3D(p2.X - p3.X, p2.Y - p3.Y, p2.Z - p3.Z);
  138. //判断是否平行(x,y,z)与(a,b,c)平行的条件。 xb - ya=0,xc - za = 0, yc - zb = 0
  139. var a1 = v1.X * v2.Y - v1.Y * v2.X;
  140. var a2 = v1.X * v2.Z - v1.Z * v2.X;
  141. var a3 = v1.Y * v2.Z - v1.Z * v2.Y;
  142. return Math.Abs(a1) < Precision && Math.Abs(a2) < Precision && Math.Abs(a3) < Precision;
  143. }
  144. /// <summary>
  145. /// 判断三个点是否共线
  146. /// </summary>
  147. /// <param name="point1"></param>
  148. /// <param name="point2"></param>
  149. /// <param name="point3"></param>
  150. /// <returns></returns>
  151. public static bool IsParallel(Point3DF point1, Point3DF point2, Point3DF point3)
  152. {
  153. var p1 = new Point3D((int)Math.Round(point1.X), (int)Math.Round(point1.Y), (int)Math.Round(point1.Z));
  154. var p2 = new Point3D((int)Math.Round(point2.X), (int)Math.Round(point2.Y), (int)Math.Round(point2.Z));
  155. var p3 = new Point3D((int)Math.Round(point3.X), (int)Math.Round(point3.Y), (int)Math.Round(point3.Z));
  156. return IsParallel(p1, p2, p3);
  157. }
  158. /// <summary>
  159. /// 三维空间,线段和平面的交点,endPoint1和endPoint2为线段的两个端点
  160. /// </summary>
  161. /// <param name="endPoint1"></param>
  162. /// <param name="endPoint2"></param>
  163. /// <param name="planeEquation"></param>
  164. /// <returns></returns>
  165. public static List<Point3DF> GetIntersectionOfLineAndPlane(Point3D endPoint1, Point3D endPoint2,
  166. PlaneEquation planeEquation)
  167. {
  168. var a = planeEquation.A;
  169. var b = planeEquation.B;
  170. var c = planeEquation.C;
  171. var d = planeEquation.D;
  172. var listEndPoint3D = new List<Point3DF>();
  173. //直线P1P2-----------------------------------------------------
  174. //判断直线是否在平面上
  175. var temp1 = a * endPoint1.X + b * endPoint1.Y + c * endPoint1.Z + d;
  176. var temp2 = a * endPoint2.X + b * endPoint2.Y + c * endPoint2.Z + d;
  177. if (Math.Abs(temp1) < Precision && Math.Abs(temp2) < Precision)
  178. {
  179. //直线在平面上,取端点,即p1和p2
  180. listEndPoint3D.Add(new Point3DF(endPoint1.X, endPoint1.Y, endPoint1.Z));
  181. listEndPoint3D.Add(new Point3DF(endPoint2.X, endPoint2.Y, endPoint2.Z));
  182. }
  183. if (Math.Abs(temp1) < Precision && Math.Abs(temp2) >= Precision)
  184. {
  185. //直线与平面相交,交点取P1
  186. listEndPoint3D.Add(new Point3DF(endPoint1.X, endPoint1.Y, endPoint1.Z));
  187. }
  188. if (Math.Abs(temp1) >= Precision && Math.Abs(temp2) < Precision)
  189. {
  190. //直线与平面相交,交点取P2
  191. listEndPoint3D.Add(new Point3DF(endPoint2.X, endPoint2.Y, endPoint2.Z));
  192. }
  193. if (Math.Abs(temp1) >= Precision && Math.Abs(temp2) >= Precision)
  194. {
  195. if (temp1 * temp2 < 0)
  196. {
  197. //直线与平面相交,交点取P2
  198. var x1 = endPoint1.X;
  199. var y1 = endPoint1.Y;
  200. var z1 = endPoint1.Z;
  201. var x2 = endPoint2.X;
  202. var y2 = endPoint2.Y;
  203. var z2 = endPoint2.Z;
  204. var temp = a * x1 - a * x2 + b * y1 - b * y2 + c * z1 - c * z2;
  205. var x0 = (float)(-(d * x1 - d * x2 + b * x1 * y2 - b * x2 * y1 + c * x1 * z2 - c * x2 * z1) / temp);
  206. var y0 = (float)(-(d * y1 - d * y2 - a * x1 * y2 + a * x2 * y1 + c * y1 * z2 - c * y2 * z1) / temp);
  207. var z0 = (float)(-(d * z1 - d * z2 - a * x1 * z2 + a * x2 * z1 - b * y1 * z2 + b * y2 * z1) / temp);
  208. listEndPoint3D.Add(new Point3DF(x0, y0, z0));
  209. }
  210. }
  211. return listEndPoint3D;
  212. }
  213. /// <summary>
  214. /// 去掉重复的点
  215. /// </summary>
  216. /// <param name="endPointListSrc"></param>
  217. /// <returns></returns>
  218. public static List<Point3DF> RemoveRepeatingPoint(List<Point3DF> endPointListSrc)
  219. {
  220. var endPointList = new List<Point3DF>();
  221. //去除掉重复的元素
  222. for (var i = 0; i < endPointListSrc.Count; ++i)
  223. {
  224. foreach (var endPoint1 in endPointListSrc)
  225. {
  226. if (0 == endPointList.Count)
  227. {
  228. endPointList.Add(endPoint1);
  229. }
  230. else
  231. {
  232. var isRepeat = false;
  233. foreach (var endPoint2 in endPointList)
  234. {
  235. if (IsEqualVector3D(endPoint1, endPoint2))
  236. {
  237. isRepeat = true;
  238. break;
  239. }
  240. }
  241. if (false == isRepeat)
  242. {
  243. //如果没有重复,则添加
  244. endPointList.Add(endPoint1);
  245. }
  246. }
  247. }
  248. }
  249. return endPointList;
  250. }
  251. /// <summary>
  252. /// 获得模型所有的棱
  253. /// </summary>
  254. /// <param name="modelSize"></param>
  255. /// <returns></returns>
  256. public static List<LineSegment3I> GetModelAllEdge(ModelSize modelSize)
  257. {
  258. var modelEdges = new List<LineSegment3I>();
  259. //实际上就是求长方体8个定点组成的直线与平面的交点,如果其中某条直线在平面上,则取两个端点
  260. //所有的顶点为
  261. var vertexPoint1 = new Point3D(0, 0, modelSize.ModelLengthZ - 1);
  262. var vertexPoint2 = new Point3D(0, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1);
  263. var vertexPoint3 = new Point3D(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1);
  264. var vertexPoint4 = new Point3D(modelSize.ModelLengthX - 1, 0, modelSize.ModelLengthZ - 1);
  265. var vertexPoint5 = new Point3D(0, 0, 0);
  266. var vertexPoint6 = new Point3D(0, modelSize.ModelLengthY - 1, 0);
  267. var vertexPoint7 = new Point3D(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, 0);
  268. var vertexPoint8 = new Point3D(modelSize.ModelLengthX - 1, 0, 0);
  269. //1.p1p2
  270. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint2 });
  271. //2.p2p3
  272. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint2, EndPointEnd = vertexPoint3 });
  273. //3.p3p4
  274. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint3, EndPointEnd = vertexPoint4 });
  275. //4.p1p4
  276. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint4 });
  277. //5.p1p5
  278. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint5 });
  279. //6.p2p6
  280. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint2, EndPointEnd = vertexPoint6 });
  281. //7.p3p7
  282. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint3, EndPointEnd = vertexPoint7 });
  283. //8.p4p8
  284. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint4, EndPointEnd = vertexPoint8 });
  285. //9.p5p6
  286. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint5, EndPointEnd = vertexPoint6 });
  287. //10.p6p7
  288. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint6, EndPointEnd = vertexPoint7 });
  289. //11.p7p8
  290. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint7, EndPointEnd = vertexPoint8 });
  291. //12.p5p8
  292. modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint5, EndPointEnd = vertexPoint8 });
  293. return modelEdges;
  294. }
  295. /// <summary>
  296. /// 获得模型和平面的交点,X坐标值相等情况
  297. /// </summary>
  298. /// <param name="xValue"></param>
  299. /// <param name="modelSize"></param>
  300. /// <returns></returns>
  301. private static List<Point3DF> GetIntersectionOfPlaneAndModelX(int xValue, ModelSize modelSize)
  302. {
  303. var endPointList = new List<Point3DF>();
  304. var zeroPoint = new Point3DF(xValue, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1);
  305. var xAxisPoint = new Point3DF(xValue, 0, modelSize.ModelLengthZ - 1);
  306. //顺时针方向加入四个交点
  307. endPointList.Add(zeroPoint);
  308. endPointList.Add(xAxisPoint);
  309. endPointList.Add(new Point3DF(xValue, 0, 0));
  310. endPointList.Add(new Point3DF(xValue, modelSize.ModelLengthY - 1, 0));
  311. return endPointList;
  312. }
  313. /// <summary>
  314. /// 获得模型和平面的交点,Y坐标值相等情况
  315. /// </summary>
  316. /// <param name="yValue"></param>
  317. /// <param name="modelSize"></param>
  318. /// <returns></returns>
  319. private static List<Point3DF> GetIntersectionOfPlaneAndModelY(int yValue, ModelSize modelSize)
  320. {
  321. var endPointList = new List<Point3DF>();
  322. var zeroPoint = new Point3DF(modelSize.ModelLengthX - 1, yValue, modelSize.ModelLengthZ - 1);
  323. var xAxisPoint = new Point3DF(0, yValue, modelSize.ModelLengthZ - 1);
  324. //顺时针加入四个楞交点
  325. endPointList.Add(zeroPoint);
  326. endPointList.Add(xAxisPoint);
  327. endPointList.Add(new Point3DF(0, yValue, 0));
  328. endPointList.Add(new Point3DF(modelSize.ModelLengthX - 1, yValue, 0));
  329. return endPointList;
  330. }
  331. /// <summary>
  332. /// 获得模型和平面的交点,Z坐标值相等情况
  333. /// </summary>
  334. /// <param name="zValue"></param>
  335. /// <param name="modelSize"></param>
  336. /// <returns></returns>
  337. private static List<Point3DF> GetIntersectionOfPlaneAndModelZ(int zValue, ModelSize modelSize)
  338. {
  339. var endPointList = new List<Point3DF>();
  340. var zeroPoint = new Point3DF(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, zValue);
  341. var xAxisPoint = new Point3DF(0, modelSize.ModelLengthY - 1, zValue);
  342. //顺时针4个楞交点
  343. endPointList.Add(zeroPoint);
  344. endPointList.Add(xAxisPoint);
  345. endPointList.Add(new Point3DF(0, 0, zValue));
  346. endPointList.Add(new Point3DF(modelSize.ModelLengthX - 1, 0, zValue));
  347. return endPointList;
  348. }
  349. /// <summary>
  350. /// 获得模型和平面的交点,一般情况
  351. /// </summary>
  352. /// <param name="planeEquation"></param>
  353. /// <param name="modelSize"></param>
  354. /// <returns></returns>
  355. private static List<Point3DF> GetIntersectionOfPlaneAndModelNomal(PlaneEquation planeEquation, ModelSize modelSize)
  356. {
  357. //获得模型所有的棱
  358. var modelEdges = GetModelAllEdge(modelSize);
  359. var endPointList1 = new List<Point3DF>();
  360. foreach (var edge in modelEdges)
  361. {
  362. endPointList1.AddRange(GetIntersectionOfLineAndPlane(edge.EndPointBegin, edge.EndPointEnd,
  363. planeEquation));
  364. }
  365. //去掉重复的端点
  366. var endPointList2 = RemoveRepeatingPoint(endPointList1);
  367. //确保端点在立方体上
  368. var endPointList = new List<Point3DF>();
  369. foreach (var endPoint in endPointList2)
  370. {
  371. if (IsInModel(endPoint, modelSize))
  372. {
  373. endPointList.Add(endPoint);
  374. }
  375. }
  376. return endPointList;
  377. }
  378. /// <summary>
  379. /// 判断点是否在模型内
  380. /// </summary>
  381. /// <param name="point3D"></param>
  382. /// <param name="modelSize"></param>
  383. /// <returns></returns>
  384. public static bool IsInModel(Point3DF point3D, ModelSize modelSize)
  385. {
  386. var valueMin = NegPrecision;
  387. var xMax = modelSize.ModelLengthX - 1 + Precision;
  388. var yMax = modelSize.ModelLengthY - 1 + Precision;
  389. var zMax = modelSize.ModelLengthZ - 1 + Precision;
  390. return point3D.X > valueMin && point3D.Y > valueMin && point3D.Z > valueMin &&
  391. point3D.X < xMax && point3D.Y < yMax && point3D.Z < zMax;
  392. }
  393. /// <summary>
  394. /// 获得模型和平面的交点
  395. /// </summary>
  396. /// <param name="one3DPlaneThreeBasicPoints"></param>
  397. /// <param name="modelSize"></param>
  398. /// <param name="sliceType"></param>
  399. /// <returns></returns>
  400. public static List<Point3DF> GetIntersectionOfPlaneAndModel(One3DPlaneThreeBasicPoints one3DPlaneThreeBasicPoints,
  401. ModelSize modelSize, ModelSliceType sliceType = ModelSliceType.Normal)
  402. {
  403. switch (sliceType)
  404. {
  405. case ModelSliceType.XEqual:
  406. return GetIntersectionOfPlaneAndModelX((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.X), modelSize);
  407. case ModelSliceType.YEqual:
  408. return GetIntersectionOfPlaneAndModelY((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.Y), modelSize);
  409. case ModelSliceType.ZEqual:
  410. return GetIntersectionOfPlaneAndModelZ((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.Z), modelSize);
  411. case ModelSliceType.Normal:
  412. //一般情况下获取切片
  413. var planeEquation = GetPlaneEquation(one3DPlaneThreeBasicPoints.PointA, one3DPlaneThreeBasicPoints.PointB,
  414. one3DPlaneThreeBasicPoints.PointC);
  415. return GetIntersectionOfPlaneAndModelNomal(planeEquation, modelSize);
  416. default:
  417. return new List<Point3DF>();
  418. }
  419. }
  420. /// <summary>
  421. /// 获得对应的图像端点坐标
  422. /// </summary>
  423. /// <param name="endPointList3D"></param>
  424. /// <returns></returns>
  425. private static List<Point2D> GetRotatedImageEndPointsX(List<Point3DF> endPointList3D)
  426. {
  427. var endPointList2D = new List<Point2D>();
  428. var width = (int)Math.Round(endPointList3D[0].Y);
  429. var height = (int)Math.Round(endPointList3D[0].Z);
  430. //四个端点, 顺时针方向加入2D点
  431. endPointList2D.Add(new Point2D(0, 0));
  432. endPointList2D.Add(new Point2D(width, 0));
  433. endPointList2D.Add(new Point2D(width, height));
  434. endPointList2D.Add(new Point2D(0, height));
  435. return endPointList2D;
  436. }
  437. /// <summary>
  438. /// 获得对应的图像端点坐标
  439. /// </summary>
  440. /// <param name="endPointList3D"></param>
  441. /// <returns></returns>
  442. private static List<Point2D> GetRotatedImageEndPointsY(List<Point3DF> endPointList3D)
  443. {
  444. var endPointList2D = new List<Point2D>();
  445. var width = (int)Math.Round(endPointList3D[0].X);
  446. var height = (int)Math.Round(endPointList3D[0].Z);
  447. //四个端点, 顺时针方向加入2D点
  448. endPointList2D.Add(new Point2D(0, 0));
  449. endPointList2D.Add(new Point2D(width, 0));
  450. endPointList2D.Add(new Point2D(width, height));
  451. endPointList2D.Add(new Point2D(0, height));
  452. return endPointList2D;
  453. }
  454. /// <summary>
  455. /// 获得对应的图像端点坐标
  456. /// </summary>
  457. /// <param name="endPointList3D"></param>
  458. /// <returns></returns>
  459. private static List<Point2D> GetRotatedImageEndPointsZ(List<Point3DF> endPointList3D)
  460. {
  461. var endPointList2D = new List<Point2D>();
  462. var width = (int)Math.Round(endPointList3D[0].X);
  463. var height = (int)Math.Round(endPointList3D[0].Y);
  464. //四个端点, 顺时针方向加入2D点
  465. endPointList2D.Add(new Point2D(0, 0));
  466. endPointList2D.Add(new Point2D(width, 0));
  467. endPointList2D.Add(new Point2D(width, height));
  468. endPointList2D.Add(new Point2D(0, height));
  469. return endPointList2D;
  470. }
  471. /// <summary>
  472. ///获得旋转后平面对应的零点三维坐标
  473. /// </summary>
  474. /// <param name="maxEndPoint"></param>
  475. /// <param name="nearPointX"></param>
  476. /// <param name="nearPointY"></param>
  477. /// <returns></returns>
  478. public static One2DPlaneThreeBasic3DPoints GetOne2DPlaneBasicPoints(List<Point3DF> endPointList3D)
  479. {
  480. try
  481. {
  482. //获得最大的端点----------------------------------
  483. var maxEndPoint = GetMaxPoint(endPointList3D);
  484. //获得与最大端点相邻的两个端点
  485. GetTwoMinDistancePoint(maxEndPoint, endPointList3D, out var nearPointX, out var nearPointY);
  486. //以maxEndPoint和nearPointX为二维图的x轴,方向maxEndPoint指向nearPointX
  487. //求向量maxEndPoint--nearPointX与向量maxEndPoint--nearPointY的夹角是否大于90,
  488. //如果大于90度则maxEndPoint点不能作为(0.0)点,因为此时以maxEndPoint为零点的话nearPointY的x坐标值为负数,
  489. //为了保证图像点都为正,需要以过nearPointY点,垂直于x轴的直线与x轴的的交点作为零点
  490. //cosA = u·v / | u || v |,如果cosA > 0 ,则小于90度,原点取maxEndPoint
  491. var vector1 = GetVector3D(maxEndPoint, nearPointX);
  492. var vector2 = GetVector3D(maxEndPoint, nearPointY);
  493. var cosA = GetCosA3D(vector1, vector2);
  494. var zeroPoint = cosA < NegPrecision ? GetZeroPoint(maxEndPoint, nearPointX, nearPointY) : maxEndPoint;
  495. return new One2DPlaneThreeBasic3DPoints
  496. {
  497. ZeroPoint = zeroPoint,
  498. XAxisPoint = nearPointX,
  499. YAxisPoint = nearPointY
  500. };
  501. }
  502. catch (Exception e)
  503. {
  504. LogHelper.ErrorLog("MathTools3D GetOne2DPlaneBasicPoints error," + e.Message + "," + e.StackTrace);
  505. return new One2DPlaneThreeBasic3DPoints
  506. {
  507. ZeroPoint = new Point3DF(0, 0, 0),
  508. XAxisPoint = new Point3DF(0, 0, 0),
  509. YAxisPoint = new Point3DF(0, 0, 0)
  510. };
  511. }
  512. }
  513. /// <summary>
  514. /// 求平面的(0,0)点对应的三维坐标
  515. /// </summary>
  516. /// <param name="maxPoint"></param>
  517. /// <param name="nearPointX"></param>
  518. /// <param name="nearPointY"></param>
  519. /// <returns></returns>
  520. private static Point3DF GetZeroPoint(Point3DF maxPoint, Point3DF nearPointX, Point3DF nearPointY)
  521. {
  522. var x1 = nearPointX.X;
  523. var y1 = nearPointX.Y;
  524. var z1 = nearPointX.Z;
  525. var x2 = nearPointY.X;
  526. var y2 = nearPointY.Y;
  527. var z2 = nearPointY.Z;
  528. var xm = maxPoint.X;
  529. var ym = maxPoint.Y;
  530. var zm = maxPoint.Z;
  531. var denominator = (xm - x1) * (xm - x1) + (ym - y1) * (ym - y1) + (zm - z1) * (zm - z1);
  532. var e = x2 * xm - x1 * x2 + (y2 * ym - y1 * y2) + (z2 * zm - z1 * z2);
  533. var x0 = (e - x1 * (xm - x1) - (ym - y1) * y1 - z1 * (zm - z1)) * (xm - x1);
  534. x0 = x0 / denominator + x1;
  535. var y0 = (ym - y1) * e - x1 * (xm - x1) * (ym - y1) - (ym - y1) * (ym - y1) * y1 - z1 * (zm - z1) * (ym - y1);
  536. y0 = y0 / denominator + y1;
  537. var z0 = (e - x1 * (xm - x1) - (ym - y1) * y1 - z1 * (zm - z1)) * (zm - z1);
  538. z0 = z0 / denominator + z1;
  539. return new Point3DF(x0, y0, z0);
  540. }
  541. /// <summary>
  542. /// 计算三维世界点,旋转平移变换后的图像端点坐标
  543. /// </summary>
  544. /// <param name="endPointList3D"></param>
  545. /// <param name="sliceType"></param>
  546. /// <returns></returns>
  547. public static List<Point2D> GetRotatedImageEndPoints(List<Point3DF> endPointList3D, One2DPlaneThreeBasic3DPoints plane2DBasic3DPoints,
  548. ModelSliceType sliceType = ModelSliceType.Normal)
  549. {
  550. switch (sliceType)
  551. {
  552. case ModelSliceType.XEqual:
  553. return GetRotatedImageEndPointsX(endPointList3D);
  554. case ModelSliceType.YEqual:
  555. return GetRotatedImageEndPointsY(endPointList3D);
  556. case ModelSliceType.ZEqual:
  557. return GetRotatedImageEndPointsZ(endPointList3D);
  558. case ModelSliceType.Normal:
  559. return Chang3DTo2D(endPointList3D, plane2DBasic3DPoints);
  560. default:
  561. return new List<Point2D>();
  562. }
  563. }
  564. /// <summary>
  565. /// 计算两点间的距离
  566. /// </summary>
  567. /// <param name="pointA"></param>
  568. /// <param name="pointB"></param>
  569. /// <returns></returns>
  570. public static double GetTwoPointDistance(Point3DF pointA, Point3DF pointB)
  571. {
  572. var disX = pointA.X - pointB.X;
  573. var disY = pointA.Y - pointB.Y;
  574. var disZ = pointA.Z - pointB.Z;
  575. return Math.Sqrt(disX * disX + disY * disY + disZ * disZ);
  576. }
  577. /// <summary>
  578. /// 计算两点间的距离的平方
  579. /// </summary>
  580. /// <param name="pointA"></param>
  581. /// <param name="pointB"></param>
  582. /// <returns></returns>
  583. public static double GetTwoPointDistancePow2(Point3DF pointA, Point3DF pointB)
  584. {
  585. var disX = pointA.X - pointB.X;
  586. var disY = pointA.Y - pointB.Y;
  587. var disZ = pointA.Z - pointB.Z;
  588. return disX * disX + disY * disY + disZ * disZ;
  589. }
  590. /// <summary>
  591. /// 求距离maxEndPoint最近的点,如果存在多个点,则返回这些点中最大点
  592. /// </summary>
  593. /// <param name="maxEndPoint"></param>
  594. /// <param name="endPointList3D"></param>
  595. /// <returns></returns>
  596. public static Point3DF GetMinDistancePoint(Point3DF maxEndPoint, List<Point3DF> endPointList3D)
  597. {
  598. var nearPointX = new Point3DF();
  599. double dis = 0;
  600. var count = 0;
  601. foreach (var point in endPointList3D)
  602. {
  603. //判断是否是maxEndPoint点
  604. if (IsEqualVector3D(point, maxEndPoint))
  605. {
  606. continue;
  607. }
  608. //求距离
  609. var disTemp = GetTwoPointDistance(maxEndPoint, point);
  610. if (0 == count)
  611. {
  612. dis = disTemp;
  613. nearPointX.X = point.X;
  614. nearPointX.Y = point.Y;
  615. nearPointX.Z = point.Z;
  616. }
  617. if (count > 0)
  618. {
  619. if (TwoDoubleEqual(disTemp, dis))
  620. {
  621. if (ComparePoint3D(point, nearPointX))
  622. {
  623. dis = disTemp;
  624. nearPointX.X = point.X;
  625. nearPointX.Y = point.Y;
  626. nearPointX.Z = point.Z;
  627. }
  628. }
  629. }
  630. ++count;
  631. }
  632. return nearPointX;
  633. }
  634. /// <summary>
  635. /// 判断两个三维点是否相等
  636. /// </summary>
  637. /// <param name="point1"></param>
  638. /// <param name="point2"></param>
  639. /// <returns></returns>
  640. public static bool IsEqualVector3D(Point3DF point1, Point3DF point2)
  641. {
  642. return TwoDoubleEqual(point1.X, point2.X) && TwoDoubleEqual(point1.Y, point2.Y) && TwoDoubleEqual(point1.Z, point2.Z);
  643. }
  644. /// <summary>
  645. /// 获得三维向量
  646. /// </summary>
  647. /// <param name="pointStart"></param>
  648. /// <param name="pointEnd"></param>
  649. /// <returns></returns>
  650. public static Point3DF GetVector3D(Point3DF pointStart, Point3DF pointEnd)
  651. {
  652. return new Point3DF(pointEnd.X - pointStart.X, pointEnd.Y - pointStart.Y, pointEnd.Z - pointStart.Z);
  653. }
  654. /// <summary>
  655. /// 获得整数点向量
  656. /// </summary>
  657. /// <param name="pointStart"></param>
  658. /// <param name="pointEnd"></param>
  659. /// <returns></returns>
  660. public static Point2D GetVector2D(Point2D pointStart, Point2D pointEnd)
  661. {
  662. return new Point2D(pointEnd.X - pointStart.X, pointEnd.Y - pointStart.Y);
  663. }
  664. /// <summary>
  665. /// 求三维向量之间的夹角
  666. /// </summary>
  667. /// <param name="vector1"></param>
  668. /// <param name="vector2"></param>
  669. /// <returns></returns>
  670. public static double GetCosA3D(Point3DF vector1, Point3DF vector2)
  671. {
  672. if (IsEqualVector3D(vector1, new Point3DF(0, 0, 0)))
  673. {
  674. return 1;
  675. }
  676. if (IsEqualVector3D(vector2, new Point3DF(0, 0, 0)))
  677. {
  678. return 1;
  679. }
  680. var distanceX = GetTwoPointDistance(new Point3DF(0, 0, 0), vector1);
  681. var distanceY = GetTwoPointDistance(new Point3DF(0, 0, 0), vector2);
  682. if (Math.Abs(distanceX) < Precision)
  683. {
  684. return 1;
  685. }
  686. if (Math.Abs(distanceY) < Precision)
  687. {
  688. return 1;
  689. }
  690. //cosA = u·v / | u || v |,
  691. return (vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z) / (distanceX * distanceY);
  692. }
  693. /// <summary>
  694. /// 计算二维向量夹角的余弦值
  695. /// </summary>
  696. /// <param name="v1"></param>
  697. /// <param name="v2"></param>
  698. /// <returns></returns>
  699. public static double GetCosA2D(Point2D v1, Point2D v2)
  700. {
  701. if (v1.Equals(new Point2D(0, 0)))
  702. {
  703. return 1;
  704. }
  705. if (v2.Equals(new Point2D(0, 0)))
  706. {
  707. return 1;
  708. }
  709. var d1 = Math.Sqrt(Math.Abs(v1.X * v1.X + v1.Y * v1.Y));
  710. var d2 = Math.Sqrt(Math.Abs(v2.X * v2.X + v2.Y * v2.Y));
  711. if (Math.Abs(d1) < Precision || Math.Abs(d2) < Precision)
  712. {
  713. return 1;
  714. }
  715. return (v1.X * v2.X + v1.Y + v2.Y) / (d1 * d2);
  716. }
  717. /// <summary>
  718. /// 找最大点两个边的端点,大的点作为X轴坐标
  719. /// </summary>
  720. /// <param name="maxEndPoint"></param>
  721. /// <param name="endPointList3D"></param>
  722. /// <param name="nearPointX"></param>
  723. /// <param name="nearPoinitY"></param>
  724. private static void GetTwoMinDistancePoint(Point3DF maxEndPoint, List<Point3DF> endPointList3D, out Point3DF nearPointX, out Point3DF nearPoinitY)
  725. {
  726. nearPointX = new Point3DF();
  727. nearPoinitY = new Point3DF();
  728. nearPointX = GetMinDistancePoint(maxEndPoint, endPointList3D);
  729. var vector1 = GetVector3D(maxEndPoint, nearPointX);
  730. double minCosA = 2;
  731. //求与maxEndPoint--pD1的夹角最大的点
  732. foreach (var point in endPointList3D)
  733. {
  734. //判断是否是pD1点
  735. if (IsEqualVector3D(point, nearPointX) || IsEqualVector3D(point, maxEndPoint))
  736. {
  737. continue;
  738. }
  739. var vector2 = GetVector3D(maxEndPoint, point);
  740. var cosA = GetCosA3D(vector1, vector2);
  741. if (cosA < minCosA)
  742. {
  743. minCosA = cosA;
  744. nearPoinitY.X = point.X;
  745. nearPoinitY.Y = point.Y;
  746. nearPoinitY.Z = point.Z;
  747. }
  748. }
  749. if (!ComparePoint3D(nearPointX, nearPoinitY))
  750. {
  751. var temp = new Point3DF { X = nearPoinitY.X, Y = nearPoinitY.Y, Z = nearPoinitY.Z };
  752. nearPoinitY.X = nearPointX.X;
  753. nearPoinitY.Y = nearPointX.Y;
  754. nearPoinitY.Z = nearPointX.Z;
  755. nearPointX.X = temp.X;
  756. nearPointX.Y = temp.Y;
  757. nearPointX.Z = temp.Z;
  758. }
  759. }
  760. /// <summary>
  761. /// 获得端点中最大的点
  762. /// </summary>
  763. /// <param name="endPointList3D"></param>
  764. /// <returns></returns>
  765. private static Point3DF GetMaxPoint(IEnumerable<Point3DF> endPointList3D)
  766. {
  767. var maxPoint = new Point3DF(0, 0, 0);
  768. foreach (var point in endPointList3D)
  769. {
  770. if (ComparePoint3D(point, maxPoint))
  771. {
  772. maxPoint.X = point.X;
  773. maxPoint.Y = point.Y;
  774. maxPoint.Z = point.Z;
  775. }
  776. }
  777. return maxPoint;
  778. }
  779. /// <summary>
  780. /// 两个三维点大小比较,先按z排序,再按y排序,再按x排序
  781. /// </summary>
  782. /// <param name="point1"></param>
  783. /// <param name="point2"></param>
  784. /// <returns></returns>
  785. public static bool ComparePoint3D(Point3DF point1, Point3DF point2)
  786. {
  787. if (TwoDoubleEqual(point1.Z, point2.Z))
  788. {
  789. if (TwoDoubleEqual(point1.Y, point2.Y))
  790. {
  791. if (TwoDoubleEqual(point1.X, point2.X))
  792. {
  793. return false;
  794. }
  795. return point1.X > point2.X;
  796. }
  797. return point1.Y > point2.Y;
  798. }
  799. return point1.Z > point2.Z;
  800. }
  801. /// <summary>
  802. /// 获得模型切片的类型
  803. /// </summary>
  804. /// <param name="basicPoints"></param>
  805. /// <returns></returns>
  806. public static ModelSliceType GetModelSliceType(One3DPlaneThreeBasicPoints basicPoints)
  807. {
  808. //三个端点X坐标相等的情况
  809. if (TwoDoubleEqual(basicPoints.PointA.X, basicPoints.PointB.X) &&
  810. TwoDoubleEqual(basicPoints.PointA.X, basicPoints.PointC.X) &&
  811. TwoDoubleEqual(basicPoints.PointB.X, basicPoints.PointC.X))
  812. {
  813. return ModelSliceType.XEqual;
  814. }
  815. //三个端点Y坐标相等的情况
  816. if (TwoDoubleEqual(basicPoints.PointA.Y, basicPoints.PointB.Y) &&
  817. TwoDoubleEqual(basicPoints.PointA.Y, basicPoints.PointC.Y) &&
  818. TwoDoubleEqual(basicPoints.PointB.Y, basicPoints.PointC.Y))
  819. {
  820. return ModelSliceType.YEqual;
  821. }
  822. //三个端点Z坐标相等的情况
  823. if (TwoDoubleEqual(basicPoints.PointA.Z, basicPoints.PointB.Z) &&
  824. TwoDoubleEqual(basicPoints.PointA.Z, basicPoints.PointC.Z) &&
  825. TwoDoubleEqual(basicPoints.PointB.Z, basicPoints.PointC.Z))
  826. {
  827. return ModelSliceType.ZEqual;
  828. }
  829. return ModelSliceType.Normal;
  830. }
  831. /// <summary>
  832. /// 计算切面的旋转矩阵
  833. /// </summary>
  834. /// <param name="basicPoints3D"></param>
  835. /// <param name="basicPoints2D"></param>
  836. /// <returns></returns>
  837. public static CoordinateTransformation3D GetCoordinateTransformationParameter(One2DPlaneThreeBasic3DPoints basicPoints3D,
  838. One2DPlaneThreeBasic2DPoints basicPoints2D)
  839. {
  840. var coordinateTransformation3D = new CoordinateTransformation3D
  841. {
  842. TranslationMatrix = new double[3],
  843. RotationMatrix = new double[9]
  844. };
  845. coordinateTransformation3D.TranslationMatrix[0] = basicPoints3D.ZeroPoint.X;
  846. coordinateTransformation3D.TranslationMatrix[1] = basicPoints3D.ZeroPoint.Y;
  847. coordinateTransformation3D.TranslationMatrix[2] = basicPoints3D.ZeroPoint.Z;
  848. //3D的ZeroPoint对应2D的ZeroPoint,3D的XAxisPoint对应2D的XAxisPoint,3D的YAxisPoint对应2D的YAxisPoint
  849. //XAxisPoint 2D
  850. var a1 = basicPoints2D.XAxisPoint.X;
  851. //YAxisPoint 2D
  852. var a2 = basicPoints2D.YAxisPoint.X;
  853. var b2 = basicPoints2D.YAxisPoint.Y;
  854. if (a1 == 0)
  855. {
  856. LogHelper.ErrorLog("MathTools3D GetCoordinateTransformationParameter error,The width of the plane after rotation is 0");
  857. return coordinateTransformation3D;
  858. }
  859. if (b2 == 0)
  860. {
  861. LogHelper.ErrorLog("MathTools3D GetCoordinateTransformationParameter error,The height of the plane after rotation is 0");
  862. return coordinateTransformation3D;
  863. }
  864. //3D的ZeroPoint
  865. var x0 = basicPoints3D.ZeroPoint.X;
  866. var y0 = basicPoints3D.ZeroPoint.Y;
  867. var z0 = basicPoints3D.ZeroPoint.Z;
  868. //XAxisPoint 3D
  869. var x1 = basicPoints3D.XAxisPoint.X;
  870. var y1 = basicPoints3D.XAxisPoint.Y;
  871. var z1 = basicPoints3D.XAxisPoint.Z;
  872. //YAxisPoint 3D
  873. var x2 = basicPoints3D.YAxisPoint.X;
  874. var y2 = basicPoints3D.YAxisPoint.Y;
  875. var z2 = basicPoints3D.YAxisPoint.Z;
  876. //RotationMatrix[1 2 3
  877. //4 5 6
  878. //7 8 9]
  879. //第一个和第二个分量
  880. coordinateTransformation3D.RotationMatrix[0] = (x1 - x0) / a1;
  881. coordinateTransformation3D.RotationMatrix[1] = (x2 - x0) / b2 + (a2 * x0 - a2 * x1) / (a1 * b2);
  882. //第4个和第5个分量
  883. coordinateTransformation3D.RotationMatrix[3] = (y1 - y0) / a1;
  884. coordinateTransformation3D.RotationMatrix[4] = (y2 - y0) / b2 + (a2 * y0 - a2 * y1) / (a1 * b2);
  885. //coordinateTransformation3D
  886. coordinateTransformation3D.RotationMatrix[6] = (z1 - z0) / a1;
  887. //m[7] = (a2 * z0 + a1 * z2 - a1 * z0 - a2 * z1) / (a1*b2);
  888. coordinateTransformation3D.RotationMatrix[7] = (z2 - z0) / b2 + (a2 * z0 - a2 * z1) / (a1 * b2);
  889. return coordinateTransformation3D;
  890. }
  891. /// <summary>
  892. /// 多个三维点转图像点
  893. /// </summary>
  894. /// <param name="endPointList3D"></param>
  895. /// <param name="basicPoints"></param>
  896. /// <returns></returns>
  897. public static List<Point2D> Chang3DTo2D(List<Point3DF> endPointList3D, One2DPlaneThreeBasic3DPoints basicPoints)
  898. {
  899. var endPointList2I = new List<Point2D>();
  900. var zeroPoint = basicPoints.ZeroPoint;
  901. var xAxisPoint = basicPoints.XAxisPoint;
  902. //旋转后,图像x轴上的点
  903. var disX = GetTwoPointDistance(zeroPoint, xAxisPoint);
  904. foreach (var point3D in endPointList3D)
  905. {
  906. if (IsEqualVector3D(zeroPoint, point3D))
  907. {
  908. endPointList2I.Add(new Point2D(0, 0));
  909. continue;
  910. }
  911. //求目标点到原点和nearPointX的距离的平方
  912. var d1 = GetTwoPointDistancePow2(point3D, zeroPoint);
  913. var d2 = GetTwoPointDistancePow2(point3D, xAxisPoint);
  914. //src_point的横坐标是d1*cos(a),a是目标点与原点和m1点之间的夹角
  915. //由极坐标公式推出
  916. var a2 = (d1 - d2 + disX * disX) / 2 / disX;
  917. var b2 = Math.Sqrt(Math.Abs(d1 - a2 * a2));
  918. endPointList2I.Add(new Point2D((int)Math.Round(a2), (int)Math.Round(b2)));
  919. }
  920. return endPointList2I;
  921. }
  922. /// <summary>
  923. /// 按照顺时针排序端点
  924. /// </summary>
  925. /// <param name="endPointList3D"></param>
  926. /// <param name="endPointList2I"></param>
  927. /// <param name="zeroPoint"></param>
  928. public static void SortEndPointClockwise(One2DPlaneThreeBasic2DPoints basicPoints, List<Point3DF> endPointList3D, List<Point2D> endPointList2I)
  929. {
  930. var num = endPointList3D.Count;
  931. if (num < 3)
  932. {
  933. return;
  934. }
  935. var vectorX = GetVector2D(new Point2D(0, 0), basicPoints.XAxisPoint);
  936. var endPointStruct = new List<EndPointStruct>();
  937. for (var i = 0; i < num; ++i)
  938. {
  939. var vector1 = GetVector2D(new Point2D(0, 0), endPointList2I[i]);
  940. var temp = new EndPointStruct
  941. {
  942. EndPoint3D = endPointList3D[i],
  943. EndPoint2I = endPointList2I[i],
  944. CosA = GetCosA2D(vectorX, vector1)
  945. };
  946. temp.Molecule = vectorX.X * vector1.X + vectorX.Y * vector1.Y;
  947. temp.Denominator = (int)(Math.Sqrt(vectorX.X * vectorX.X + vectorX.Y * vectorX.Y) * Math.Sqrt(vector1.X * vector1.X + vector1.Y * vector1.Y));
  948. endPointStruct.Add(temp);
  949. }
  950. //从大到小排列
  951. endPointStruct.Sort(CompareEndPointStruct);
  952. endPointList3D.Clear();
  953. endPointList2I.Clear();
  954. foreach (var pointStruct in endPointStruct)
  955. {
  956. endPointList3D.Add(pointStruct.EndPoint3D);
  957. endPointList2I.Add(pointStruct.EndPoint2I);
  958. }
  959. }
  960. /// <summary>
  961. /// 结构体大小比较
  962. /// </summary>
  963. /// <param name="point1"></param>
  964. /// <param name="point2"></param>
  965. /// <returns></returns>
  966. public static int CompareEndPointStruct(EndPointStruct point1, EndPointStruct point2)
  967. {
  968. var smaller = 1;
  969. var bigger = -1;
  970. if (point1.EndPoint2I.X == 0 && point1.EndPoint2I.Y == 0)
  971. {
  972. return bigger;
  973. }
  974. if (point2.EndPoint2I.X == 0 && point2.EndPoint2I.Y == 0)
  975. {
  976. return smaller;
  977. }
  978. if (point1.EndPoint2I.Y == 0 && point2.EndPoint2I.Y == 0)
  979. {
  980. if (point1.EndPoint2I.X < point2.EndPoint2I.X)
  981. {
  982. return bigger;
  983. }
  984. if (point1.EndPoint2I.X > point2.EndPoint2I.X)
  985. {
  986. return smaller;
  987. }
  988. }
  989. if (point1.EndPoint2I.X == 0 && point2.EndPoint2I.X == 0)
  990. {
  991. if (point1.EndPoint2I.Y < point2.EndPoint2I.Y)
  992. {
  993. return smaller;
  994. }
  995. if (point1.EndPoint2I.Y > point2.EndPoint2I.Y)
  996. {
  997. return bigger;
  998. }
  999. }
  1000. if (point1.EndPoint2I.Y == 0 && point2.EndPoint2I.Y != 0)
  1001. {
  1002. return bigger;
  1003. }
  1004. if (point1.EndPoint2I.Y != 0 && point2.EndPoint2I.Y == 0)
  1005. {
  1006. return smaller;
  1007. }
  1008. if (point1.EndPoint2I.X == 0 && point1.EndPoint2I.Y != 0 && point2.EndPoint2I.X != 0)
  1009. {
  1010. return smaller;
  1011. }
  1012. if (point2.EndPoint2I.X == 0 && point2.EndPoint2I.Y != 0 && point1.EndPoint2I.X != 0)
  1013. {
  1014. return bigger;
  1015. }
  1016. if (point1.CosA - point2.CosA < NegPrecision)
  1017. {
  1018. return smaller;
  1019. }
  1020. if (point1.CosA - point2.CosA > Precision)
  1021. {
  1022. return bigger;
  1023. }
  1024. if (point1.Molecule * point2.Denominator < point2.Molecule * point1.Denominator)
  1025. {
  1026. return smaller;
  1027. }
  1028. if (point1.Molecule * point2.Denominator > point2.Molecule * point1.Denominator)
  1029. {
  1030. return bigger;
  1031. }
  1032. if (point1.EndPoint2I.X < point2.EndPoint2I.X)
  1033. {
  1034. return bigger;
  1035. }
  1036. if (point1.EndPoint2I.X > point2.EndPoint2I.X)
  1037. {
  1038. return smaller;
  1039. }
  1040. if (point1.EndPoint2I.Y < point2.EndPoint2I.Y)
  1041. {
  1042. return smaller;
  1043. }
  1044. if (point1.EndPoint2I.Y > point2.EndPoint2I.Y)
  1045. {
  1046. return bigger;
  1047. }
  1048. return 0;
  1049. }
  1050. /// <summary>
  1051. /// 将模型切面的三个基础点坐标转成二维坐标
  1052. /// </summary>
  1053. /// <param name="basicPoints"></param>
  1054. /// <returns></returns>
  1055. public static One2DPlaneThreeBasic2DPoints ChangePlaneBasic3DPointTo2D(One2DPlaneThreeBasic3DPoints basicPoints)
  1056. {
  1057. var zeroPoint3D = basicPoints.ZeroPoint;
  1058. //旋转后,图像x轴上的点
  1059. var nearPointX3D = basicPoints.XAxisPoint;
  1060. var nearPointY3D = basicPoints.YAxisPoint;
  1061. var disX = GetTwoPointDistance(basicPoints.ZeroPoint, basicPoints.XAxisPoint);
  1062. //求目标点到原点和nearPointX的距离
  1063. var d1 = GetTwoPointDistancePow2(nearPointY3D, zeroPoint3D);
  1064. var d2 = GetTwoPointDistancePow2(nearPointY3D, nearPointX3D);
  1065. //src_point的横坐标是d1*cos(a),a是目标点与原点和m1点之间的夹角
  1066. //由极坐标公式推出
  1067. var a2 = (d1 - d2 + disX * disX) / 2 / disX;
  1068. var b2 = Math.Sqrt(Math.Abs(d1 - a2 * a2));
  1069. var zeroPoint2D = new Point2D(0, 0);
  1070. var nearPointX2D = new Point2D((int)Math.Round(disX), 0);
  1071. var nearPointY2D = new Point2D((int)Math.Round(a2), (int)Math.Round(b2));
  1072. return new One2DPlaneThreeBasic2DPoints
  1073. {
  1074. ZeroPoint = zeroPoint2D,
  1075. XAxisPoint = nearPointX2D,
  1076. YAxisPoint = nearPointY2D
  1077. };
  1078. }
  1079. /// <summary>
  1080. /// 获取2的最小次幂的值
  1081. /// </summary>
  1082. /// <param name="inputValue">input value</param>
  1083. /// <returns></returns>
  1084. public static int GetMinPowOfTwo(int inputValue)
  1085. {
  1086. for (var i = 4; i < int.MaxValue; i++)
  1087. {
  1088. var sum = (int)Math.Pow(2, i);
  1089. if (sum >= inputValue)
  1090. {
  1091. return sum;
  1092. }
  1093. }
  1094. return 64;
  1095. }
  1096. /// <summary>
  1097. /// 调整坐标点精度,四舍五入
  1098. /// </summary>
  1099. /// <param name="inputValue">input value</param>
  1100. /// <returns></returns>
  1101. public static Point3DF ChangePrecision(Point3DF value)
  1102. {
  1103. var x = (float)Math.Round(value.X, 3, MidpointRounding.AwayFromZero);
  1104. var y = (float)Math.Round(value.Y, 3, MidpointRounding.AwayFromZero);
  1105. var z = (float)Math.Round(value.Z, 3, MidpointRounding.AwayFromZero);
  1106. return new Point3DF(x, y, z);
  1107. }
  1108. }
  1109. }