1、二维点:
public class XPoint
{
public double X { get; set; }
public double Y { get; set; }
public XPoint()
{
X = double.NaN;
Y = double.NaN;
}
public XPoint(double x, double y)
{
X = x;
Y = y;
}
/// <summary>
/// 两点之间的距离
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public static double Distance(XPoint p1, XPoint p2)
{
return Math.Sqrt((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));
}
/// <summary>
/// 判断点坐标中是否包含无效值
/// </summary>
/// <param name="pnt"></param>
/// <returns></returns>
public static bool IsNaN(XPoint pnt)
{
if (double.IsNaN(pnt.X) || double.IsNaN(pnt.Y))
{
return true;
}
return false;
}
/// <summary>
/// 判断四个点是否构成一个矩形(适当放宽矩形的精度控制,已提高适应性)
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <param name="p4"></param>
/// <param name="tol">精度</param>
/// <returns></returns>
public static bool JugeRect(XPoint p1, XPoint p2, XPoint p3, XPoint p4, double tol = 0.001)
{
double xy = Math.Max(Math.Abs(p3.X - p1.X), Math.Abs(p3.Y - p1.Y));
bool flag1 = Math.Abs(p1.Y - p2.Y) < tol * 10 * xy;
bool flag2 = Math.Abs(p3.Y - p4.Y) < tol * 10 * xy;
bool flag3 = Math.Abs(p1.X - p4.X) < tol * 10 * xy;
bool flag4 = Math.Abs(p2.X - p3.X) < tol * 10 * xy;
return flag1 && flag2 && flag3 && flag4;
}
}
2、二维线段:
public class XLine
{
public XPoint StartPt { get; set; }
public XPoint EndPt { get; set; }
/// <summary>
/// 线段由多段构成时,去掉中间的空隙,剩余部分相对于起点距离比例的闭区间
/// </summary>
public XRangeList Range { get; set; }
public XLine(XPoint start, XPoint end)
{
StartPt = start;
EndPt = end;
Range = new XRangeList();
Range.Merge(new XRange(0, 1));
}
/// <summary>
/// 线段长度
/// </summary>
/// <returns></returns>
public double Length()
{
//勾股定理
return Math.Sqrt((this.EndPt.X - this.StartPt.X) * (this.EndPt.X - this.StartPt.X) + (this.EndPt.Y - this.StartPt.Y) * (this.EndPt.Y - this.StartPt.Y));
}
/// <summary>
/// 判断点是否在线段有效区间内
/// </summary>
/// <param name="pnt"></param>
/// <returns></returns>
public bool In(XPoint pnt)
{
double dx = this.EndPt.X - this.StartPt.X;
double dy = this.EndPt.Y - this.StartPt.Y;
if (Math.Abs(dx) > Math.Abs(dy))
{
double v = (pnt.X - this.StartPt.X) / dx;
return this.Range.In(v);
}
else
{
double v = (pnt.Y - this.StartPt.Y) / dy;
return this.Range.In(v);
}
}
/// <summary>
/// 判断两条线段是否平行
/// </summary>
/// <param name="lineA">线段A</param>
/// <param name="lineB">线段B</param>
/// <returns>true:平行,反之</returns>
public static bool IsParallel(XLine lineA, XLine lineB)
{
bool flagA = lineA.StartPt.X == lineA.EndPt.X;
bool flagB = lineB.StartPt.X == lineB.EndPt.X;
if (flagA && flagB)
{
//两条垂直线
return true;
}
else if (flagA || flagB)
{
//一条垂直一条不垂直
return false;
}
else
{
//利用斜率进行判断
var slopeA = (lineA.EndPt.Y - lineA.StartPt.Y) / (lineA.EndPt.X - lineA.StartPt.X);
var slopeB = (lineB.EndPt.Y - lineB.StartPt.Y) / (lineB.EndPt.X - lineB.StartPt.X);
return slopeA == slopeB;
}
}
/// <summary>
/// 获取两条线段的交点
/// </summary>
/// <param name="lineM">线段M</param>
/// <param name="lineN">线段N</param>
/// <returns>相交则返回交点坐标,否则返回null</returns>
public static XPoint IntersectWith(XLine lineM, XLine lineN, double tol = 0.001)
{
if (IsParallel(lineM, lineN))
{
return null;
}
//已知直线上的两点A(x1,y1),B(x2,y2)
//则有:A*x1 + B*y1 + C = A*x2 + B*y2 + C
//变形得:A(x1 - x2) = B(y2 - y1)
//求得:A = y2 - y1,B = x1 - x2,C = x2*y1 - x1*y2
//线段M中的各常数(取百万分之一的容差)
var constA_m = Math.Round(lineM.EndPt.Y - lineM.StartPt.Y, 6);
var constB_m = Math.Round(lineM.StartPt.X - lineM.EndPt.X, 6);
var constC_m = Math.Round(lineM.EndPt.X * lineM.StartPt.Y - lineM.StartPt.X * lineM.EndPt.Y, 6);
//线段N中的各常数(取百万分之一的容差)
var constA_n = Math.Round(lineN.EndPt.Y - lineN.StartPt.Y, 6);
var constB_n = Math.Round(lineN.StartPt.X - lineN.EndPt.X, 6);
var constC_n = Math.Round(lineN.EndPt.X * lineN.StartPt.Y - lineN.StartPt.X * lineN.EndPt.Y, 6);
double istPtX, istPtY;
if (constA_m == 0)
{
//线段M平行于X轴
istPtY = -1 * constC_m / constB_m;
if (constB_n == 0)
{
istPtX = -1 * constC_n / constA_n;
}
else
{
istPtX = -1 * (constB_n * istPtY + constC_n) / constA_n;//使用线段N的直线方程求交点Y值
}
}
else if (constB_m == 0)
{
//线段M平行于Y轴
istPtX = -1 * constC_m / constA_m;
if (constA_n == 0)
{
istPtY = -1 * constC_n / constB_n;
}
else
{
istPtY = -1 * (constA_m * istPtX + constC_m) / constB_m;//使用线段M的直线方程求交点Y值
}
}
else if (constA_n == 0)
{
//线段N平行于X轴
istPtY = -1 * constC_n / constB_n;
if (constB_m == 0)
{
istPtX = -1 * constC_m / constA_m;
}
else
{
istPtX = -1 * (constB_m * istPtY + constC_m) / constA_m;//使用线段M的直线方程求交点Y值
}
}
else if (constB_n == 0)
{
//线段N平行于Y轴
istPtX = -1 * constC_n / constA_n;
if (constA_m == 0)
{
istPtY = -1 * constC_m / constB_m;
}
else
{
istPtY = -1 * (constA_n * istPtX + constC_n) / constB_n;//使用线段M的直线方程求交点Y值
}
}
else
{
istPtX = (constB_n * constC_m - constB_m * constC_n) / (constA_n * constB_m - constA_m * constB_n);//求交点X值(两个直线方程带入)
istPtY = -1 * (constA_m * istPtX + constC_m) / constB_m;//使用线段A的直线方程求交点Y值
}
var minX_m = Math.Min(lineM.StartPt.X, lineM.EndPt.X);
var maxX_m = Math.Max(lineM.StartPt.X, lineM.EndPt.X);
var minY_m = Math.Min(lineM.StartPt.Y, lineM.EndPt.Y);
var maxY_m = Math.Max(lineM.StartPt.Y, lineM.EndPt.Y);
var flagA = istPtX >= minX_m - tol && istPtX <= maxX_m + tol && istPtY >= minY_m - tol && istPtY <= maxY_m + tol;
var minX_n = Math.Min(lineN.StartPt.X, lineN.EndPt.X);
var maxX_n = Math.Max(lineN.StartPt.X, lineN.EndPt.X);
var minY_n = Math.Min(lineN.StartPt.Y, lineN.EndPt.Y);
var maxY_n = Math.Max(lineN.StartPt.Y, lineN.EndPt.Y);
var flagB = istPtX >= minX_n - tol && istPtX <= maxX_n + tol && istPtY >= minY_n - tol && istPtY <= maxY_n + tol;
//判断交点是否在两条线段上
if (flagA && flagB)
{
return new XPoint(istPtX, istPtY);
}
return null;
}
/// <summary>
/// xline合并,参数要求:在同一条直线内,方向一致,且已排好序
/// </summary>
/// <param name="lineList"></param>
/// <returns></returns>
public static XLine Merge(List<XLine> lineList)
{
if (lineList.Count == 0)
{
return null;
}
else if (lineList.Count == 1)
{
return lineList[0];
}
else
{
XPoint start = lineList[0].StartPt;
XPoint end = lineList[0].EndPt;
foreach (XLine item in lineList)
{
if (XPoint.Distance(item.EndPt, start) > XPoint.Distance(start, end))
{
end = item.EndPt;
}
}
XLine xline = new XLine(start, end);
double len = xline.Length();
List<XRange> xRanges = new List<XRange>();
for (int i = 0; i < lineList.Count; i++)
{
double s = XPoint.Distance(lineList[i].StartPt, start) / len;
double t = XPoint.Distance(lineList[i].EndPt, start) / len;
xRanges.Add(new XRange(s, t));
}
xline.Range.List = XRangeList.Merge(xRanges);
return xline;
}
}
/// <summary>
/// 判断两条线段的起点端点在误差范围内是否相连
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="rol"></param>
/// <returns></returns>
public static bool LineJoint(XLine a, XLine b, double rol = 0.001)
{
if (System.Object.ReferenceEquals(a, b)) return true;
if (System.Object.ReferenceEquals(a, null) || System.Object.ReferenceEquals(b, null)) return false;
if (Math.Abs(a.StartPt.X - b.StartPt.X) < rol && Math.Abs(a.StartPt.Y - b.StartPt.Y) < rol) //起点相连
{
return true;
}
if (Math.Abs(a.StartPt.X - b.EndPt.X) < rol && Math.Abs(a.StartPt.Y - b.EndPt.Y) < rol)//起终点相连
{
return true;
}
if (Math.Abs(a.EndPt.X - b.StartPt.X) < rol && Math.Abs(a.EndPt.Y - b.StartPt.Y) < rol)//终起点相连
{
return true;
}
if (Math.Abs(a.EndPt.X - b.EndPt.X) < rol && Math.Abs(a.EndPt.Y - b.EndPt.Y) < rol)//终点相连
{
return true;
}
return false;
}
#region CAD二开中使用的方法,需引用Autodesk.AutoCAD.Geometry;
基于CAD的起终点
//public Point2d CadStartPt { get; set; }
//public Point2d CadEndPt { get; set; }
/ <summary>
/ 方向
/ </summary>
//public Vector2d Direction
//{
// get
// {
// Vector2d direction = CadEndPt - CadStartPt;
// return direction;
// }
//}
/ <summary>
/ 判断两向量是否是平行向量(方向相反也是平行向量)
/ 备注:此方法基于CAD
/ </summary>
/ <param name="v1"></param>
/ <param name="v2"></param>
/ <returns></returns>
//static public bool Parallel(Vector2d v1, Vector2d v2, double tol = 0.001)
//{
// if (Math.Abs(v1.Angle - v2.Angle) < tol)
// {
// return true;
// }
// else if (Math.Abs(Math.Abs(v1.Angle - v2.Angle) - Math.PI) < tol)
// {
// return true;
// }
// return false;
//}
/ <summary>
/ 平面两线段交点
/ 备注:此方法基于CAD
/ </summary>
/ <param name="line1"></param>
/ <param name="line2"></param>
/ <param name="tol">精度控制值,必须为正值,默认为0</param>
/ <returns></returns>
//public static Point2d Intersect(XLine line1, XLine line2, double tol = 0)
//{
// //Line1: Line1.startPt + s * Line1.direction for s in [0,1]
// //Line2: Line1.startPt + t * Line1.direction for t in [0,1]
// if (!Parallel(line2.Direction, line1.Direction))//如果两直线平行
// {
// Vector2d v = line2.CadStartPt - line1.CadStartPt;
// Point2d E = new Point2d(v.X, v.Y);
// double kross = line1.Direction.X * line2.Direction.Y - line1.Direction.Y * line2.Direction.X;
// double s = (E.X * line2.Direction.Y - E.Y * line2.Direction.X) / kross;
// double t = (E.X * line1.Direction.Y - E.Y * line1.Direction.X) / kross;
// if (line1.Range.In(s, tol) && line2.Range.In(t, tol))
// {
// Point2d p = line1.CadStartPt + s * line1.Direction;
// return p;
// }
// else
// {
// return new Point2d(double.NaN, double.NaN);//无交点
// }
// }
// else
// {
// return new Point2d(double.NaN, double.NaN);//两线段平行或部分重合
// }
// //double sqrkross = kross * kross;
//}
#endregion
}
3、简单的平面:
public class XExtents
{
public XPoint MinPoint { get; set; }
public XPoint MaxPoint { get; set; }
public XExtents()
{
MinPoint = new XPoint();
MaxPoint = new XPoint();
}
public XExtents(XPoint minimum, XPoint maximum)
{
MinPoint = minimum;
MaxPoint = maximum;
}
public void AddPoint(XPoint xPoint)
{
if (XPoint.IsNaN(xPoint))
{
return;
}
var flagMin = XPoint.IsNaN(MinPoint);
var flagMax = XPoint.IsNaN(MaxPoint);
if (flagMin)
{
if (flagMax)
{
MinPoint = xPoint;
MaxPoint = xPoint;
}
else
{
double minx = xPoint.X < MaxPoint.X ? xPoint.X : MaxPoint.X;
double miny = xPoint.Y < MaxPoint.Y ? xPoint.Y : MaxPoint.Y;
double maxx = xPoint.X > MaxPoint.X ? xPoint.X : MaxPoint.X;
double maxy = xPoint.Y > MaxPoint.Y ? xPoint.Y : MaxPoint.Y;
MinPoint = new XPoint(minx, miny);
MaxPoint = new XPoint(maxx, maxy);
}
}
else
{
if (flagMax)
{
double minx = xPoint.X < MinPoint.X ? xPoint.X : MinPoint.X;
double miny = xPoint.Y < MinPoint.Y ? xPoint.Y : MinPoint.Y;
double maxx = xPoint.X > MinPoint.X ? xPoint.X : MinPoint.X;
double maxy = xPoint.Y > MinPoint.Y ? xPoint.Y : MinPoint.Y;
MinPoint = new XPoint(minx, miny);
MaxPoint = new XPoint(maxx, maxy);
}
else
{
double minx = xPoint.X < MinPoint.X ? xPoint.X : MinPoint.X;
double miny = xPoint.Y < MinPoint.Y ? xPoint.Y : MinPoint.Y;
double maxx = xPoint.X > MaxPoint.X ? xPoint.X : MaxPoint.X;
double maxy = xPoint.Y > MaxPoint.Y ? xPoint.Y : MaxPoint.Y;
MinPoint = new XPoint(minx, miny);
MaxPoint = new XPoint(maxx, maxy);
}
}
}
}