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);
}
}
}