using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; using AI.Common; using AI.Common.Log; using AI.Common.Tools; namespace AI.Reconstruction { /// /// 计算切面的三个点, 3维点坐标 /// public struct One2DPlaneThreeBasic3DPoints { public Point3DF ZeroPoint; public Point3DF XAxisPoint; public Point3DF YAxisPoint; } /// /// 计算切面的三个点, 2维点坐标 /// public struct One2DPlaneThreeBasic2DPoints { public Point2D ZeroPoint; public Point2D XAxisPoint; public Point2D YAxisPoint; } /// /// 计算切面的三个点 /// public struct One3DPlaneThreeBasicPoints { public Point3DF PointA; public Point3DF PointB; public Point3DF PointC; } /// /// 平面方程Ax+By+CZ+D=0; /// public struct PlaneEquation { public double A; public double B; public double C; public double D; } /// /// 三维空间线段 /// public struct LineSegment3I { //线段开始的端点 public Point3D EndPointBegin; //线段结束的端点 public Point3D EndPointEnd; } /// /// 三维坐标变换 /// public struct CoordinateTransformation3D { public double[] RotationMatrix; public double[] TranslationMatrix; } /// /// 切片端点的世界点和图像点,cosA是图像点向量与图像X轴的夹角余弦值 /// public struct EndPointStruct { public Point3DF EndPoint3D; public Point2D EndPoint2I; public double CosA; //分子 public long Molecule; //分母 public long Denominator; } public class MathTools3D { //精度要求 public static float Precision = 0.0001f; //精度要求 public static float NegPrecision = -0.0001f; public static bool TwoDoubleEqual(double d1, double d2) { return Math.Abs(d1 - d2) < Precision; } /// /// 根据三个点计算平面方程 /// /// /// /// /// public static PlaneEquation GetPlaneEquation(Point3DF point1, Point3DF point2, Point3DF point3) { try { if (IsParallel(point1, point2, point3)) { LogHelper.ErrorLog("MathTools3D GetPlaneEquation, three points is in one line."); return new PlaneEquation { A = 0, B = 0, C = 0, D = 0 }; } var x1 = point1.X; var y1 = point1.Y; var z1 = point1.Z; var x2 = point2.X; var y2 = point2.Y; var z2 = point2.Z; var x3 = point3.X; var y3 = point3.Y; var z3 = point3.Z; //平面方程Ax+By+CZ+D=0; var a = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2); var b = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2); var c = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2); var d = -x1 * (y2 * z3 - y3 * z2) - x2 * (y3 * z1 - y1 * z3) - x3 * (y1 * z2 - y2 * z1); return new PlaneEquation { A = a, B = b, C = c, D = d }; } catch (Exception e) { LogHelper.ErrorLog("MathTools3D GetPlaneEquation error," + e.Message + "," + e.StackTrace); return new PlaneEquation { A = 0, B = 0, C = 0, D = 0 }; } } /// /// 判断三个点是否共线 /// /// /// /// /// public static bool IsParallel(Point3D p1, Point3D p2, Point3D p3) { var v1 = new Point3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z); var v2 = new Point3D(p2.X - p3.X, p2.Y - p3.Y, p2.Z - p3.Z); //判断是否平行(x,y,z)与(a,b,c)平行的条件。 xb - ya=0,xc - za = 0, yc - zb = 0 var a1 = v1.X * v2.Y - v1.Y * v2.X; var a2 = v1.X * v2.Z - v1.Z * v2.X; var a3 = v1.Y * v2.Z - v1.Z * v2.Y; return Math.Abs(a1) < Precision && Math.Abs(a2) < Precision && Math.Abs(a3) < Precision; } /// /// 判断三个点是否共线 /// /// /// /// /// public static bool IsParallel(Point3DF point1, Point3DF point2, Point3DF point3) { var p1 = new Point3D((int)Math.Round(point1.X), (int)Math.Round(point1.Y), (int)Math.Round(point1.Z)); var p2 = new Point3D((int)Math.Round(point2.X), (int)Math.Round(point2.Y), (int)Math.Round(point2.Z)); var p3 = new Point3D((int)Math.Round(point3.X), (int)Math.Round(point3.Y), (int)Math.Round(point3.Z)); return IsParallel(p1, p2, p3); } /// /// 三维空间,线段和平面的交点,endPoint1和endPoint2为线段的两个端点 /// /// /// /// /// public static List GetIntersectionOfLineAndPlane(Point3D endPoint1, Point3D endPoint2, PlaneEquation planeEquation) { var a = planeEquation.A; var b = planeEquation.B; var c = planeEquation.C; var d = planeEquation.D; var listEndPoint3D = new List(); //直线P1P2----------------------------------------------------- //判断直线是否在平面上 var temp1 = a * endPoint1.X + b * endPoint1.Y + c * endPoint1.Z + d; var temp2 = a * endPoint2.X + b * endPoint2.Y + c * endPoint2.Z + d; if (Math.Abs(temp1) < Precision && Math.Abs(temp2) < Precision) { //直线在平面上,取端点,即p1和p2 listEndPoint3D.Add(new Point3DF(endPoint1.X, endPoint1.Y, endPoint1.Z)); listEndPoint3D.Add(new Point3DF(endPoint2.X, endPoint2.Y, endPoint2.Z)); } if (Math.Abs(temp1) < Precision && Math.Abs(temp2) >= Precision) { //直线与平面相交,交点取P1 listEndPoint3D.Add(new Point3DF(endPoint1.X, endPoint1.Y, endPoint1.Z)); } if (Math.Abs(temp1) >= Precision && Math.Abs(temp2) < Precision) { //直线与平面相交,交点取P2 listEndPoint3D.Add(new Point3DF(endPoint2.X, endPoint2.Y, endPoint2.Z)); } if (Math.Abs(temp1) >= Precision && Math.Abs(temp2) >= Precision) { if (temp1 * temp2 < 0) { //直线与平面相交,交点取P2 var x1 = endPoint1.X; var y1 = endPoint1.Y; var z1 = endPoint1.Z; var x2 = endPoint2.X; var y2 = endPoint2.Y; var z2 = endPoint2.Z; var temp = a * x1 - a * x2 + b * y1 - b * y2 + c * z1 - c * z2; var x0 = (float)(-(d * x1 - d * x2 + b * x1 * y2 - b * x2 * y1 + c * x1 * z2 - c * x2 * z1) / temp); var y0 = (float)(-(d * y1 - d * y2 - a * x1 * y2 + a * x2 * y1 + c * y1 * z2 - c * y2 * z1) / temp); var z0 = (float)(-(d * z1 - d * z2 - a * x1 * z2 + a * x2 * z1 - b * y1 * z2 + b * y2 * z1) / temp); listEndPoint3D.Add(new Point3DF(x0, y0, z0)); } } return listEndPoint3D; } /// /// 去掉重复的点 /// /// /// public static List RemoveRepeatingPoint(List endPointListSrc) { var endPointList = new List(); //去除掉重复的元素 for (var i = 0; i < endPointListSrc.Count; ++i) { foreach (var endPoint1 in endPointListSrc) { if (0 == endPointList.Count) { endPointList.Add(endPoint1); } else { var isRepeat = false; foreach (var endPoint2 in endPointList) { if (IsEqualVector3D(endPoint1, endPoint2)) { isRepeat = true; break; } } if (false == isRepeat) { //如果没有重复,则添加 endPointList.Add(endPoint1); } } } } return endPointList; } /// /// 获得模型所有的棱 /// /// /// public static List GetModelAllEdge(ModelSize modelSize) { var modelEdges = new List(); //实际上就是求长方体8个定点组成的直线与平面的交点,如果其中某条直线在平面上,则取两个端点 //所有的顶点为 var vertexPoint1 = new Point3D(0, 0, modelSize.ModelLengthZ - 1); var vertexPoint2 = new Point3D(0, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1); var vertexPoint3 = new Point3D(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1); var vertexPoint4 = new Point3D(modelSize.ModelLengthX - 1, 0, modelSize.ModelLengthZ - 1); var vertexPoint5 = new Point3D(0, 0, 0); var vertexPoint6 = new Point3D(0, modelSize.ModelLengthY - 1, 0); var vertexPoint7 = new Point3D(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, 0); var vertexPoint8 = new Point3D(modelSize.ModelLengthX - 1, 0, 0); //1.p1p2 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint2 }); //2.p2p3 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint2, EndPointEnd = vertexPoint3 }); //3.p3p4 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint3, EndPointEnd = vertexPoint4 }); //4.p1p4 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint4 }); //5.p1p5 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint1, EndPointEnd = vertexPoint5 }); //6.p2p6 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint2, EndPointEnd = vertexPoint6 }); //7.p3p7 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint3, EndPointEnd = vertexPoint7 }); //8.p4p8 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint4, EndPointEnd = vertexPoint8 }); //9.p5p6 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint5, EndPointEnd = vertexPoint6 }); //10.p6p7 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint6, EndPointEnd = vertexPoint7 }); //11.p7p8 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint7, EndPointEnd = vertexPoint8 }); //12.p5p8 modelEdges.Add(new LineSegment3I { EndPointBegin = vertexPoint5, EndPointEnd = vertexPoint8 }); return modelEdges; } /// /// 获得模型和平面的交点,X坐标值相等情况 /// /// /// /// private static List GetIntersectionOfPlaneAndModelX(int xValue, ModelSize modelSize) { var endPointList = new List(); var zeroPoint = new Point3DF(xValue, modelSize.ModelLengthY - 1, modelSize.ModelLengthZ - 1); var xAxisPoint = new Point3DF(xValue, 0, modelSize.ModelLengthZ - 1); //顺时针方向加入四个交点 endPointList.Add(zeroPoint); endPointList.Add(xAxisPoint); endPointList.Add(new Point3DF(xValue, 0, 0)); endPointList.Add(new Point3DF(xValue, modelSize.ModelLengthY - 1, 0)); return endPointList; } /// /// 获得模型和平面的交点,Y坐标值相等情况 /// /// /// /// private static List GetIntersectionOfPlaneAndModelY(int yValue, ModelSize modelSize) { var endPointList = new List(); var zeroPoint = new Point3DF(modelSize.ModelLengthX - 1, yValue, modelSize.ModelLengthZ - 1); var xAxisPoint = new Point3DF(0, yValue, modelSize.ModelLengthZ - 1); //顺时针加入四个楞交点 endPointList.Add(zeroPoint); endPointList.Add(xAxisPoint); endPointList.Add(new Point3DF(0, yValue, 0)); endPointList.Add(new Point3DF(modelSize.ModelLengthX - 1, yValue, 0)); return endPointList; } /// /// 获得模型和平面的交点,Z坐标值相等情况 /// /// /// /// private static List GetIntersectionOfPlaneAndModelZ(int zValue, ModelSize modelSize) { var endPointList = new List(); var zeroPoint = new Point3DF(modelSize.ModelLengthX - 1, modelSize.ModelLengthY - 1, zValue); var xAxisPoint = new Point3DF(0, modelSize.ModelLengthY - 1, zValue); //顺时针4个楞交点 endPointList.Add(zeroPoint); endPointList.Add(xAxisPoint); endPointList.Add(new Point3DF(0, 0, zValue)); endPointList.Add(new Point3DF(modelSize.ModelLengthX - 1, 0, zValue)); return endPointList; } /// /// 获得模型和平面的交点,一般情况 /// /// /// /// private static List GetIntersectionOfPlaneAndModelNomal(PlaneEquation planeEquation, ModelSize modelSize) { //获得模型所有的棱 var modelEdges = GetModelAllEdge(modelSize); var endPointList1 = new List(); foreach (var edge in modelEdges) { endPointList1.AddRange(GetIntersectionOfLineAndPlane(edge.EndPointBegin, edge.EndPointEnd, planeEquation)); } //去掉重复的端点 var endPointList2 = RemoveRepeatingPoint(endPointList1); //确保端点在立方体上 var endPointList = new List(); foreach (var endPoint in endPointList2) { if (IsInModel(endPoint, modelSize)) { endPointList.Add(endPoint); } } return endPointList; } /// /// 判断点是否在模型内 /// /// /// /// public static bool IsInModel(Point3DF point3D, ModelSize modelSize) { var valueMin = NegPrecision; var xMax = modelSize.ModelLengthX - 1 + Precision; var yMax = modelSize.ModelLengthY - 1 + Precision; var zMax = modelSize.ModelLengthZ - 1 + Precision; return point3D.X > valueMin && point3D.Y > valueMin && point3D.Z > valueMin && point3D.X < xMax && point3D.Y < yMax && point3D.Z < zMax; } /// /// 获得模型和平面的交点 /// /// /// /// /// public static List GetIntersectionOfPlaneAndModel(One3DPlaneThreeBasicPoints one3DPlaneThreeBasicPoints, ModelSize modelSize, ModelSliceType sliceType = ModelSliceType.Normal) { switch (sliceType) { case ModelSliceType.XEqual: return GetIntersectionOfPlaneAndModelX((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.X), modelSize); case ModelSliceType.YEqual: return GetIntersectionOfPlaneAndModelY((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.Y), modelSize); case ModelSliceType.ZEqual: return GetIntersectionOfPlaneAndModelZ((int)Math.Round(one3DPlaneThreeBasicPoints.PointA.Z), modelSize); case ModelSliceType.Normal: //一般情况下获取切片 var planeEquation = GetPlaneEquation(one3DPlaneThreeBasicPoints.PointA, one3DPlaneThreeBasicPoints.PointB, one3DPlaneThreeBasicPoints.PointC); return GetIntersectionOfPlaneAndModelNomal(planeEquation, modelSize); default: return new List(); } } /// /// 获得对应的图像端点坐标 /// /// /// private static List GetRotatedImageEndPointsX(List endPointList3D) { var endPointList2D = new List(); var width = (int)Math.Round(endPointList3D[0].Y); var height = (int)Math.Round(endPointList3D[0].Z); //四个端点, 顺时针方向加入2D点 endPointList2D.Add(new Point2D(0, 0)); endPointList2D.Add(new Point2D(width, 0)); endPointList2D.Add(new Point2D(width, height)); endPointList2D.Add(new Point2D(0, height)); return endPointList2D; } /// /// 获得对应的图像端点坐标 /// /// /// private static List GetRotatedImageEndPointsY(List endPointList3D) { var endPointList2D = new List(); var width = (int)Math.Round(endPointList3D[0].X); var height = (int)Math.Round(endPointList3D[0].Z); //四个端点, 顺时针方向加入2D点 endPointList2D.Add(new Point2D(0, 0)); endPointList2D.Add(new Point2D(width, 0)); endPointList2D.Add(new Point2D(width, height)); endPointList2D.Add(new Point2D(0, height)); return endPointList2D; } /// /// 获得对应的图像端点坐标 /// /// /// private static List GetRotatedImageEndPointsZ(List endPointList3D) { var endPointList2D = new List(); var width = (int)Math.Round(endPointList3D[0].X); var height = (int)Math.Round(endPointList3D[0].Y); //四个端点, 顺时针方向加入2D点 endPointList2D.Add(new Point2D(0, 0)); endPointList2D.Add(new Point2D(width, 0)); endPointList2D.Add(new Point2D(width, height)); endPointList2D.Add(new Point2D(0, height)); return endPointList2D; } /// ///获得旋转后平面对应的零点三维坐标 /// /// /// /// /// public static One2DPlaneThreeBasic3DPoints GetOne2DPlaneBasicPoints(List endPointList3D) { try { //获得最大的端点---------------------------------- var maxEndPoint = GetMaxPoint(endPointList3D); //获得与最大端点相邻的两个端点 GetTwoMinDistancePoint(maxEndPoint, endPointList3D, out var nearPointX, out var nearPointY); //以maxEndPoint和nearPointX为二维图的x轴,方向maxEndPoint指向nearPointX //求向量maxEndPoint--nearPointX与向量maxEndPoint--nearPointY的夹角是否大于90, //如果大于90度则maxEndPoint点不能作为(0.0)点,因为此时以maxEndPoint为零点的话nearPointY的x坐标值为负数, //为了保证图像点都为正,需要以过nearPointY点,垂直于x轴的直线与x轴的的交点作为零点 //cosA = u·v / | u || v |,如果cosA > 0 ,则小于90度,原点取maxEndPoint var vector1 = GetVector3D(maxEndPoint, nearPointX); var vector2 = GetVector3D(maxEndPoint, nearPointY); var cosA = GetCosA3D(vector1, vector2); var zeroPoint = cosA < NegPrecision ? GetZeroPoint(maxEndPoint, nearPointX, nearPointY) : maxEndPoint; return new One2DPlaneThreeBasic3DPoints { ZeroPoint = zeroPoint, XAxisPoint = nearPointX, YAxisPoint = nearPointY }; } catch (Exception e) { LogHelper.ErrorLog("MathTools3D GetOne2DPlaneBasicPoints error," + e.Message + "," + e.StackTrace); return new One2DPlaneThreeBasic3DPoints { ZeroPoint = new Point3DF(0, 0, 0), XAxisPoint = new Point3DF(0, 0, 0), YAxisPoint = new Point3DF(0, 0, 0) }; } } /// /// 求平面的(0,0)点对应的三维坐标 /// /// /// /// /// private static Point3DF GetZeroPoint(Point3DF maxPoint, Point3DF nearPointX, Point3DF nearPointY) { var x1 = nearPointX.X; var y1 = nearPointX.Y; var z1 = nearPointX.Z; var x2 = nearPointY.X; var y2 = nearPointY.Y; var z2 = nearPointY.Z; var xm = maxPoint.X; var ym = maxPoint.Y; var zm = maxPoint.Z; var denominator = (xm - x1) * (xm - x1) + (ym - y1) * (ym - y1) + (zm - z1) * (zm - z1); var e = x2 * xm - x1 * x2 + (y2 * ym - y1 * y2) + (z2 * zm - z1 * z2); var x0 = (e - x1 * (xm - x1) - (ym - y1) * y1 - z1 * (zm - z1)) * (xm - x1); x0 = x0 / denominator + x1; var y0 = (ym - y1) * e - x1 * (xm - x1) * (ym - y1) - (ym - y1) * (ym - y1) * y1 - z1 * (zm - z1) * (ym - y1); y0 = y0 / denominator + y1; var z0 = (e - x1 * (xm - x1) - (ym - y1) * y1 - z1 * (zm - z1)) * (zm - z1); z0 = z0 / denominator + z1; return new Point3DF(x0, y0, z0); } /// /// 计算三维世界点,旋转平移变换后的图像端点坐标 /// /// /// /// public static List GetRotatedImageEndPoints(List endPointList3D, One2DPlaneThreeBasic3DPoints plane2DBasic3DPoints, ModelSliceType sliceType = ModelSliceType.Normal) { switch (sliceType) { case ModelSliceType.XEqual: return GetRotatedImageEndPointsX(endPointList3D); case ModelSliceType.YEqual: return GetRotatedImageEndPointsY(endPointList3D); case ModelSliceType.ZEqual: return GetRotatedImageEndPointsZ(endPointList3D); case ModelSliceType.Normal: return Chang3DTo2D(endPointList3D, plane2DBasic3DPoints); default: return new List(); } } /// /// 计算两点间的距离 /// /// /// /// public static double GetTwoPointDistance(Point3DF pointA, Point3DF pointB) { var disX = pointA.X - pointB.X; var disY = pointA.Y - pointB.Y; var disZ = pointA.Z - pointB.Z; return Math.Sqrt(disX * disX + disY * disY + disZ * disZ); } /// /// 计算两点间的距离的平方 /// /// /// /// public static double GetTwoPointDistancePow2(Point3DF pointA, Point3DF pointB) { var disX = pointA.X - pointB.X; var disY = pointA.Y - pointB.Y; var disZ = pointA.Z - pointB.Z; return disX * disX + disY * disY + disZ * disZ; } /// /// 求距离maxEndPoint最近的点,如果存在多个点,则返回这些点中最大点 /// /// /// /// public static Point3DF GetMinDistancePoint(Point3DF maxEndPoint, List endPointList3D) { var nearPointX = new Point3DF(); double dis = 0; var count = 0; foreach (var point in endPointList3D) { //判断是否是maxEndPoint点 if (IsEqualVector3D(point, maxEndPoint)) { continue; } //求距离 var disTemp = GetTwoPointDistance(maxEndPoint, point); if (0 == count) { dis = disTemp; nearPointX.X = point.X; nearPointX.Y = point.Y; nearPointX.Z = point.Z; } if (count > 0) { if (TwoDoubleEqual(disTemp, dis)) { if (ComparePoint3D(point, nearPointX)) { dis = disTemp; nearPointX.X = point.X; nearPointX.Y = point.Y; nearPointX.Z = point.Z; } } } ++count; } return nearPointX; } /// /// 判断两个三维点是否相等 /// /// /// /// public static bool IsEqualVector3D(Point3DF point1, Point3DF point2) { return TwoDoubleEqual(point1.X, point2.X) && TwoDoubleEqual(point1.Y, point2.Y) && TwoDoubleEqual(point1.Z, point2.Z); } /// /// 获得三维向量 /// /// /// /// public static Point3DF GetVector3D(Point3DF pointStart, Point3DF pointEnd) { return new Point3DF(pointEnd.X - pointStart.X, pointEnd.Y - pointStart.Y, pointEnd.Z - pointStart.Z); } /// /// 获得整数点向量 /// /// /// /// public static Point2D GetVector2D(Point2D pointStart, Point2D pointEnd) { return new Point2D(pointEnd.X - pointStart.X, pointEnd.Y - pointStart.Y); } /// /// 求三维向量之间的夹角 /// /// /// /// public static double GetCosA3D(Point3DF vector1, Point3DF vector2) { if (IsEqualVector3D(vector1, new Point3DF(0, 0, 0))) { return 1; } if (IsEqualVector3D(vector2, new Point3DF(0, 0, 0))) { return 1; } var distanceX = GetTwoPointDistance(new Point3DF(0, 0, 0), vector1); var distanceY = GetTwoPointDistance(new Point3DF(0, 0, 0), vector2); if (Math.Abs(distanceX) < Precision) { return 1; } if (Math.Abs(distanceY) < Precision) { return 1; } //cosA = u·v / | u || v |, return (vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z) / (distanceX * distanceY); } /// /// 计算二维向量夹角的余弦值 /// /// /// /// public static double GetCosA2D(Point2D v1, Point2D v2) { if (v1.Equals(new Point2D(0, 0))) { return 1; } if (v2.Equals(new Point2D(0, 0))) { return 1; } var d1 = Math.Sqrt(Math.Abs(v1.X * v1.X + v1.Y * v1.Y)); var d2 = Math.Sqrt(Math.Abs(v2.X * v2.X + v2.Y * v2.Y)); if (Math.Abs(d1) < Precision || Math.Abs(d2) < Precision) { return 1; } return (v1.X * v2.X + v1.Y + v2.Y) / (d1 * d2); } /// /// 找最大点两个边的端点,大的点作为X轴坐标 /// /// /// /// /// private static void GetTwoMinDistancePoint(Point3DF maxEndPoint, List endPointList3D, out Point3DF nearPointX, out Point3DF nearPoinitY) { nearPointX = new Point3DF(); nearPoinitY = new Point3DF(); nearPointX = GetMinDistancePoint(maxEndPoint, endPointList3D); var vector1 = GetVector3D(maxEndPoint, nearPointX); double minCosA = 2; //求与maxEndPoint--pD1的夹角最大的点 foreach (var point in endPointList3D) { //判断是否是pD1点 if (IsEqualVector3D(point, nearPointX) || IsEqualVector3D(point, maxEndPoint)) { continue; } var vector2 = GetVector3D(maxEndPoint, point); var cosA = GetCosA3D(vector1, vector2); if (cosA < minCosA) { minCosA = cosA; nearPoinitY.X = point.X; nearPoinitY.Y = point.Y; nearPoinitY.Z = point.Z; } } if (!ComparePoint3D(nearPointX, nearPoinitY)) { var temp = new Point3DF { X = nearPoinitY.X, Y = nearPoinitY.Y, Z = nearPoinitY.Z }; nearPoinitY.X = nearPointX.X; nearPoinitY.Y = nearPointX.Y; nearPoinitY.Z = nearPointX.Z; nearPointX.X = temp.X; nearPointX.Y = temp.Y; nearPointX.Z = temp.Z; } } /// /// 获得端点中最大的点 /// /// /// private static Point3DF GetMaxPoint(IEnumerable endPointList3D) { var maxPoint = new Point3DF(0, 0, 0); foreach (var point in endPointList3D) { if (ComparePoint3D(point, maxPoint)) { maxPoint.X = point.X; maxPoint.Y = point.Y; maxPoint.Z = point.Z; } } return maxPoint; } /// /// 两个三维点大小比较,先按z排序,再按y排序,再按x排序 /// /// /// /// public static bool ComparePoint3D(Point3DF point1, Point3DF point2) { if (TwoDoubleEqual(point1.Z, point2.Z)) { if (TwoDoubleEqual(point1.Y, point2.Y)) { if (TwoDoubleEqual(point1.X, point2.X)) { return false; } return point1.X > point2.X; } return point1.Y > point2.Y; } return point1.Z > point2.Z; } /// /// 获得模型切片的类型 /// /// /// public static ModelSliceType GetModelSliceType(One3DPlaneThreeBasicPoints basicPoints) { //三个端点X坐标相等的情况 if (TwoDoubleEqual(basicPoints.PointA.X, basicPoints.PointB.X) && TwoDoubleEqual(basicPoints.PointA.X, basicPoints.PointC.X) && TwoDoubleEqual(basicPoints.PointB.X, basicPoints.PointC.X)) { return ModelSliceType.XEqual; } //三个端点Y坐标相等的情况 if (TwoDoubleEqual(basicPoints.PointA.Y, basicPoints.PointB.Y) && TwoDoubleEqual(basicPoints.PointA.Y, basicPoints.PointC.Y) && TwoDoubleEqual(basicPoints.PointB.Y, basicPoints.PointC.Y)) { return ModelSliceType.YEqual; } //三个端点Z坐标相等的情况 if (TwoDoubleEqual(basicPoints.PointA.Z, basicPoints.PointB.Z) && TwoDoubleEqual(basicPoints.PointA.Z, basicPoints.PointC.Z) && TwoDoubleEqual(basicPoints.PointB.Z, basicPoints.PointC.Z)) { return ModelSliceType.ZEqual; } return ModelSliceType.Normal; } /// /// 计算切面的旋转矩阵 /// /// /// /// public static CoordinateTransformation3D GetCoordinateTransformationParameter(One2DPlaneThreeBasic3DPoints basicPoints3D, One2DPlaneThreeBasic2DPoints basicPoints2D) { var coordinateTransformation3D = new CoordinateTransformation3D { TranslationMatrix = new double[3], RotationMatrix = new double[9] }; coordinateTransformation3D.TranslationMatrix[0] = basicPoints3D.ZeroPoint.X; coordinateTransformation3D.TranslationMatrix[1] = basicPoints3D.ZeroPoint.Y; coordinateTransformation3D.TranslationMatrix[2] = basicPoints3D.ZeroPoint.Z; //3D的ZeroPoint对应2D的ZeroPoint,3D的XAxisPoint对应2D的XAxisPoint,3D的YAxisPoint对应2D的YAxisPoint //XAxisPoint 2D var a1 = basicPoints2D.XAxisPoint.X; //YAxisPoint 2D var a2 = basicPoints2D.YAxisPoint.X; var b2 = basicPoints2D.YAxisPoint.Y; if (a1 == 0) { LogHelper.ErrorLog("MathTools3D GetCoordinateTransformationParameter error,The width of the plane after rotation is 0"); return coordinateTransformation3D; } if (b2 == 0) { LogHelper.ErrorLog("MathTools3D GetCoordinateTransformationParameter error,The height of the plane after rotation is 0"); return coordinateTransformation3D; } //3D的ZeroPoint var x0 = basicPoints3D.ZeroPoint.X; var y0 = basicPoints3D.ZeroPoint.Y; var z0 = basicPoints3D.ZeroPoint.Z; //XAxisPoint 3D var x1 = basicPoints3D.XAxisPoint.X; var y1 = basicPoints3D.XAxisPoint.Y; var z1 = basicPoints3D.XAxisPoint.Z; //YAxisPoint 3D var x2 = basicPoints3D.YAxisPoint.X; var y2 = basicPoints3D.YAxisPoint.Y; var z2 = basicPoints3D.YAxisPoint.Z; //RotationMatrix[1 2 3 //4 5 6 //7 8 9] //第一个和第二个分量 coordinateTransformation3D.RotationMatrix[0] = (x1 - x0) / a1; coordinateTransformation3D.RotationMatrix[1] = (x2 - x0) / b2 + (a2 * x0 - a2 * x1) / (a1 * b2); //第4个和第5个分量 coordinateTransformation3D.RotationMatrix[3] = (y1 - y0) / a1; coordinateTransformation3D.RotationMatrix[4] = (y2 - y0) / b2 + (a2 * y0 - a2 * y1) / (a1 * b2); //coordinateTransformation3D coordinateTransformation3D.RotationMatrix[6] = (z1 - z0) / a1; //m[7] = (a2 * z0 + a1 * z2 - a1 * z0 - a2 * z1) / (a1*b2); coordinateTransformation3D.RotationMatrix[7] = (z2 - z0) / b2 + (a2 * z0 - a2 * z1) / (a1 * b2); return coordinateTransformation3D; } /// /// 多个三维点转图像点 /// /// /// /// public static List Chang3DTo2D(List endPointList3D, One2DPlaneThreeBasic3DPoints basicPoints) { var endPointList2I = new List(); var zeroPoint = basicPoints.ZeroPoint; var xAxisPoint = basicPoints.XAxisPoint; //旋转后,图像x轴上的点 var disX = GetTwoPointDistance(zeroPoint, xAxisPoint); foreach (var point3D in endPointList3D) { if (IsEqualVector3D(zeroPoint, point3D)) { endPointList2I.Add(new Point2D(0, 0)); continue; } //求目标点到原点和nearPointX的距离的平方 var d1 = GetTwoPointDistancePow2(point3D, zeroPoint); var d2 = GetTwoPointDistancePow2(point3D, xAxisPoint); //src_point的横坐标是d1*cos(a),a是目标点与原点和m1点之间的夹角 //由极坐标公式推出 var a2 = (d1 - d2 + disX * disX) / 2 / disX; var b2 = Math.Sqrt(Math.Abs(d1 - a2 * a2)); endPointList2I.Add(new Point2D((int)Math.Round(a2), (int)Math.Round(b2))); } return endPointList2I; } /// /// 按照顺时针排序端点 /// /// /// /// public static void SortEndPointClockwise(One2DPlaneThreeBasic2DPoints basicPoints, List endPointList3D, List endPointList2I) { var num = endPointList3D.Count; if (num < 3) { return; } var vectorX = GetVector2D(new Point2D(0, 0), basicPoints.XAxisPoint); var endPointStruct = new List(); for (var i = 0; i < num; ++i) { var vector1 = GetVector2D(new Point2D(0, 0), endPointList2I[i]); var temp = new EndPointStruct { EndPoint3D = endPointList3D[i], EndPoint2I = endPointList2I[i], CosA = GetCosA2D(vectorX, vector1) }; temp.Molecule = vectorX.X * vector1.X + vectorX.Y * vector1.Y; temp.Denominator = (int)(Math.Sqrt(vectorX.X * vectorX.X + vectorX.Y * vectorX.Y) * Math.Sqrt(vector1.X * vector1.X + vector1.Y * vector1.Y)); endPointStruct.Add(temp); } //从大到小排列 endPointStruct.Sort(CompareEndPointStruct); endPointList3D.Clear(); endPointList2I.Clear(); foreach (var pointStruct in endPointStruct) { endPointList3D.Add(pointStruct.EndPoint3D); endPointList2I.Add(pointStruct.EndPoint2I); } } /// /// 结构体大小比较 /// /// /// /// public static int CompareEndPointStruct(EndPointStruct point1, EndPointStruct point2) { var smaller = 1; var bigger = -1; if (point1.EndPoint2I.X == 0 && point1.EndPoint2I.Y == 0) { return bigger; } if (point2.EndPoint2I.X == 0 && point2.EndPoint2I.Y == 0) { return smaller; } if (point1.EndPoint2I.Y == 0 && point2.EndPoint2I.Y == 0) { if (point1.EndPoint2I.X < point2.EndPoint2I.X) { return bigger; } if (point1.EndPoint2I.X > point2.EndPoint2I.X) { return smaller; } } if (point1.EndPoint2I.X == 0 && point2.EndPoint2I.X == 0) { if (point1.EndPoint2I.Y < point2.EndPoint2I.Y) { return smaller; } if (point1.EndPoint2I.Y > point2.EndPoint2I.Y) { return bigger; } } if (point1.EndPoint2I.Y == 0 && point2.EndPoint2I.Y != 0) { return bigger; } if (point1.EndPoint2I.Y != 0 && point2.EndPoint2I.Y == 0) { return smaller; } if (point1.EndPoint2I.X == 0 && point1.EndPoint2I.Y != 0 && point2.EndPoint2I.X != 0) { return smaller; } if (point2.EndPoint2I.X == 0 && point2.EndPoint2I.Y != 0 && point1.EndPoint2I.X != 0) { return bigger; } if (point1.CosA - point2.CosA < NegPrecision) { return smaller; } if (point1.CosA - point2.CosA > Precision) { return bigger; } if (point1.Molecule * point2.Denominator < point2.Molecule * point1.Denominator) { return smaller; } if (point1.Molecule * point2.Denominator > point2.Molecule * point1.Denominator) { return bigger; } if (point1.EndPoint2I.X < point2.EndPoint2I.X) { return bigger; } if (point1.EndPoint2I.X > point2.EndPoint2I.X) { return smaller; } if (point1.EndPoint2I.Y < point2.EndPoint2I.Y) { return smaller; } if (point1.EndPoint2I.Y > point2.EndPoint2I.Y) { return bigger; } return 0; } /// /// 将模型切面的三个基础点坐标转成二维坐标 /// /// /// public static One2DPlaneThreeBasic2DPoints ChangePlaneBasic3DPointTo2D(One2DPlaneThreeBasic3DPoints basicPoints) { var zeroPoint3D = basicPoints.ZeroPoint; //旋转后,图像x轴上的点 var nearPointX3D = basicPoints.XAxisPoint; var nearPointY3D = basicPoints.YAxisPoint; var disX = GetTwoPointDistance(basicPoints.ZeroPoint, basicPoints.XAxisPoint); //求目标点到原点和nearPointX的距离 var d1 = GetTwoPointDistancePow2(nearPointY3D, zeroPoint3D); var d2 = GetTwoPointDistancePow2(nearPointY3D, nearPointX3D); //src_point的横坐标是d1*cos(a),a是目标点与原点和m1点之间的夹角 //由极坐标公式推出 var a2 = (d1 - d2 + disX * disX) / 2 / disX; var b2 = Math.Sqrt(Math.Abs(d1 - a2 * a2)); var zeroPoint2D = new Point2D(0, 0); var nearPointX2D = new Point2D((int)Math.Round(disX), 0); var nearPointY2D = new Point2D((int)Math.Round(a2), (int)Math.Round(b2)); return new One2DPlaneThreeBasic2DPoints { ZeroPoint = zeroPoint2D, XAxisPoint = nearPointX2D, YAxisPoint = nearPointY2D }; } /// /// 获取2的最小次幂的值 /// /// input value /// public static int GetMinPowOfTwo(int inputValue) { for (var i = 4; i < int.MaxValue; i++) { var sum = (int)Math.Pow(2, i); if (sum >= inputValue) { return sum; } } return 64; } /// /// 调整坐标点精度,四舍五入 /// /// input value /// public static Point3DF ChangePrecision(Point3DF value) { var x = (float)Math.Round(value.X, 3, MidpointRounding.AwayFromZero); var y = (float)Math.Round(value.Y, 3, MidpointRounding.AwayFromZero); var z = (float)Math.Round(value.Z, 3, MidpointRounding.AwayFromZero); return new Point3DF(x, y, z); } } }