namespace Yw.Geometry { /// /// 直线辅助类 /// public static class Line2dHelper { /// /// 是否垂直 /// /// /// public static bool IsVerticalK(double k) { if (k >= 100000000 - 1) return true; else return false; } private const double vertical_k = 100000000;//垂直时K的值 //直线插值 public static double GetLineInsert(double X1, double X2, double Y1, double Y2, double X) { if (Math.Abs(X2 - X1) < 0.000001) { //MessageBox.Show("输入值X2与X1不能相同!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return 0; } if (Math.Abs(Y2 - Y1) < 0.000001) { //MessageBox.Show("输入值Y2与Y1不能相同!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return 0; } double Y = Y1 + (Y2 - Y1) / (X2 - X1) * (X - X1); return Y; } //是否一个点向x轴的射线穿透线段,有交点且在线的左边 public static bool IsIntersectLeft(Yw.Geometry.Point2d basePoint, Yw.Geometry.Point2d pt1, Yw.Geometry.Point2d pt2) { return IsIntersectLeft(basePoint.X, basePoint.Y, pt1.X, pt1.Y, pt2.X, pt2.Y); } public static bool IsIntersectLeft(double x, double y, double x1, double y1, double x2, double y2) { double maxY = y1 > y2 ? y1 : y2; double minY = y1 > y2 ? y2 : y1; if (Math.Abs(y2 - y1) < 0.000001) { if (Math.Abs(y - y1) < 0.000001) return true; else return false; } bool IsInLine = false; if (y < maxY && y >= minY) { if (x <= (x1 + (x2 - x1) * (y - y1) / (y2 - y1))) { IsInLine = true; } } return IsInLine; } //X1和X2之间连一条线, 在比率ratio处点的坐标 public static double GetRatioPoint(double X1, double X2, double ratio) { double X3 = 0.0; X3 = X1 + ratio * (X2 - X1); return X3; } //X1,Y1和X2 Y2之间连一条线,在X处点的Y坐标 public static double GetYbyX(double X1, double Y1, double X2, double Y2, double X) { if (Math.Abs(X1 - X2) < 0.000001) return Y1; if (Math.Abs(Y1 - Y2) < 0.000001) return Y1; double k = 0, b = 0; if (!GetKandB(X1, Y1, X2, Y2, ref k, ref b)) return Y1; double Y = 0; Y = k * X + b; return Y; } //X1,Y1和X2 Y2之间连一条线,在Y处点的X坐标 public static double GetXbyY(double X1, double Y1, double X2, double Y2, double Y) { if (Math.Abs(X1 - X2) < 0.000001) return X1; if (Math.Abs(Y1 - Y2) < 0.000001) return X1; double k = 0, b = 0; if (!GetKandB(X1, Y1, X2, Y2, ref k, ref b)) return X1; double X = (Y - b) / k; return X; } //输入(X1,Y1),(X1,Y1)生成直线,返回直线的k和b y=kx+b public static bool GetKandB(double X1, double Y1, double X2, double Y2, ref double k, ref double b) { if (Math.Abs(X1 - X2) < 0.000001) { k = vertical_k; b = Y2; return false; } else { k = (Y1 - Y2) / (X1 - X2); b = Y1 - (Y1 - Y2) * X1 / (X1 - X2); return true; } } //输入(X1,Y1),(X1,Y1)生成直线,返回直线的k和b y=kx+b public static bool GetKandB(Yw.Geometry.Point2d pt1, Yw.Geometry.Point2d pt2, ref double k, ref double b) { if (pt1 == null || pt2 == null) return false; double X1 = pt1.X; double Y1 = pt1.Y; double X2 = pt2.X; double Y2 = pt2.Y; if (Math.Abs(X1 - X2) < 0.000001) { k = vertical_k; b = Y2; return false; } else { k = (Y1 - Y2) / (X1 - X2); b = Y1 - (Y1 - Y2) * X1 / (X1 - X2); return true; } } //通过2点,得到通过这2点的直线的k,b 线的形式是 y=k*x+b,竖直返回false public static bool GetKandB(Yw.Geometry.Point2d pt1, Yw.Geometry.Point2d pt2, out double k, out double b, double ingoreDis = 0.000001) { k = 0; b = 0; if (Math.Abs(pt1.X - pt2.X) < ingoreDis) {//竖直 k = vertical_k; b = pt1.X; return false; } if (Math.Abs(pt1.Y - pt2.Y) < ingoreDis) {//平行 k = 0; b = pt1.X; return true; } k = (pt1.Y - pt2.Y) / (pt1.X - pt2.X);// Math.Atan((pt1.Y - pt2.Y) / (pt1.X - pt2.X)) * 180 / Math.PI; b = pt1.Y - k * pt1.X; return true; } //取中间点 public static Yw.Geometry.Point2d GetMiddlePoint(Yw.Geometry.Point2d pt1, Yw.Geometry.Point2d pt2) { return new Yw.Geometry.Point2d((pt1.X + pt2.X) * 0.5, (pt1.Y + pt2.Y) * 0.5); } //取内部点 public static Yw.Geometry.Point2d GetInnerPoint(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, double ratio) { if (startPt == null || endPt == null) return null; return new Yw.Geometry.Point2d(startPt.X + (endPt.X - startPt.X) * ratio, startPt.Y + (endPt.Y - startPt.Y) * ratio); } //是否是内部点 public static bool IsInnerPoint(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, Yw.Geometry.Point2d pt) { if (startPt == null || endPt == null) return false; if (pt.X < startPt.X && pt.X > endPt.X) return true; if (pt.X > startPt.X && pt.X < endPt.X) return true; return false; } //是否是内部点 public static bool IsInnerPointByX(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, Yw.Geometry.Point2d pt) { if (startPt == null || endPt == null) return false; if (pt.X < startPt.X && pt.X > endPt.X) return true; if (pt.X > startPt.X && pt.X < endPt.X) return true; return false; } // public static bool IsInnerPointByY(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, Yw.Geometry.Point2d pt) { if (startPt == null || endPt == null) return false; if (pt.Y < startPt.X && pt.Y > endPt.Y) return true; if (pt.Y > startPt.X && pt.Y < endPt.Y) return true; return false; } /// /// 计算交点(没有 就返回null) /// /// /// /// public static Yw.Geometry.Point2d GetCrossPoint(Yw.Geometry.Point2d startPt1, Yw.Geometry.Point2d endPt1, Yw.Geometry.Point2d startPt2, Yw.Geometry.Point2d endPt2) { if (startPt1 == null || endPt1 == null) return null; if (startPt2 == null || endPt2 == null) return null; double k1, b1; GetKandB(startPt1, endPt1, out k1, out b1); double k2, b2; GetKandB(startPt2, endPt2, out k2, out b2); if (Math.Abs(k1 - k2) < 0.000001) return null; if (k1 == vertical_k) {//垂直 return new Yw.Geometry.Point2d(startPt1.X, startPt1.X * k2 + b2); } if (k2 == vertical_k) {//垂直 return new Yw.Geometry.Point2d(startPt2.X, startPt2.X * k1 + b1); } double sect_x = (b2 - b1) / (k1 - k2); return new Yw.Geometry.Point2d(sect_x, sect_x * k1 + b1); } /// /// 是否平行 /// /// /// /// /// /// public static bool IsParallel(Yw.Geometry.Point2d startPt1, Yw.Geometry.Point2d endPt1, Yw.Geometry.Point2d startPt2, Yw.Geometry.Point2d endPt2) { if (startPt1 == null || endPt1 == null) return false; if (startPt2 == null || endPt2 == null) return false; double k1, b1; GetKandB(startPt1, endPt1, out k1, out b1); double k2, b2; GetKandB(startPt2, endPt2, out k2, out b2); if (Math.Abs(k1 - k2) < 0.000001) return true; else return false; } //三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3) public static Yw.Geometry.Point2d GetExtendPoint(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, double exLength) { return GetExtendPointByLength(startPt, endPt, exLength); } //三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3) public static Yw.Geometry.Point2d GetExtendPointByLength(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, double exLength) { if (startPt == null || endPt == null) return null; double betweenLength = GetPointDistance(startPt, endPt); if (betweenLength < 0.01) return startPt; double ex_ratio = (betweenLength + exLength) / betweenLength; Yw.Geometry.Point2d extPt = new Yw.Geometry.Point2d(); extPt.X = (endPt.X - startPt.X) * ex_ratio + startPt.X; extPt.Y = (endPt.Y - startPt.Y) * ex_ratio + startPt.Y; return extPt; } public static double GetPointDistance(Yw.Geometry.Point2d pt1, Yw.Geometry.Point2d pt2) { return Math.Sqrt((pt1.X - pt2.X) * (pt1.X - pt2.X) + (pt1.Y - pt2.Y) * (pt1.Y - pt2.Y)); } //三个点在同一条直线上,输入(X1,Y1),(X2,Y2)以及沿(X2,Y2)侧延长Length,得到的点(X3,Y3) public static Yw.Geometry.Point2d GetExtendPointByX(Yw.Geometry.Point2d startPt, Yw.Geometry.Point2d endPt, double exPointX) { if (startPt == null || endPt == null) return null; double X1 = startPt.X; double Y1 = startPt.Y; double X2 = endPt.X; double Y2 = endPt.Y; if (Math.Abs(X1 - X2) < 0.000001) {//竖直 return null; } else if (Math.Abs(Y1 - Y2) < 0.000001) {//竖直 return new Yw.Geometry.Point2d(exPointX, Y1); } else { //线的形式是 y = k * x + b, double k = (Y1 - Y2) / (X1 - X2); double b = Y1 - (Y1 - Y2) * X1 / (X1 - X2); double Y = k * exPointX + b; return new Yw.Geometry.Point2d(exPointX, Y); } } /// /// 求直线外一点到该直线的投影点 /// /// 线上任一点 /// 直线斜率 /// 线外指定点 /// 投影点 public static Yw.Geometry.Point2d GetProjectivePoint(Yw.Geometry.Point2d pLine, double k, Yw.Geometry.Point2d pOut) { if (pLine == null || pOut == null) return null; Yw.Geometry.Point2d pProject = new Yw.Geometry.Point2d(); if (k == 0) //垂线斜率不存在情况 { pProject.X = pOut.X; pProject.Y = pLine.Y; } else { pProject.X = (float)((k * pLine.X + pOut.X / k + pOut.Y - pLine.Y) / (1 / k + k)); pProject.Y = (float)(-1 / k * (pProject.X - pOut.X) + pOut.Y); } return pProject; } /// /// /// /// /// /// /// public static Yw.Geometry.Point2d GetProjectivePoint(Yw.Geometry.Point2d pLine1, Yw.Geometry.Point2d pLine2, Yw.Geometry.Point2d pOut) { if (pLine1 == null || pLine2 == null || pOut == null) return null; double k, b; GetKandB(pLine1, pLine2, out k, out b); if (k >= vertical_k) {//垂直 return new Yw.Geometry.Point2d(pLine1.X, pOut.Y); } return GetProjectivePoint(pLine1, k, pOut); } /// /// 点到线的距离, 注意不一定是垂直距离,点只在(line_start和line_end之间 /// /// /// /// /// public static double DistancePointToLine(Yw.Geometry.Point2d line_start, Yw.Geometry.Point2d line_end, Yw.Geometry.Point2d point) // a和b是线段的两个端点, c是检测点 { if (line_start == null || line_end == null || point == null) return 0; var project_pt = GetProjectivePoint(line_start, line_end, point); if (project_pt.X == line_start.X) {//垂直 if (IsInnerPointByY(line_start, line_end, project_pt)) return project_pt.Distance(point); } else { if (IsInnerPointByX(line_start, line_end, project_pt)) return project_pt.Distance(point); } var dis1 = line_start.Distance(point); var dis2 = line_end.Distance(point); if (dis1 < dis2) return dis1; else return dis2; } /// /// 点到线的距离, 注意不一定是垂直距离,点只在(line_start和line_end之间 /// /// /// /// /// public static double DistancePointToLine(List multi_line_start, bool isCloseCurve, Yw.Geometry.Point2d point) // a和b是线段的两个端点, c是检测点 { if (multi_line_start == null || multi_line_start.Count() < 2) return -1; double min_dis = DistancePointToLine(multi_line_start[0], multi_line_start[1], point); for (int index = 1; index < multi_line_start.Count - 1; index++) { var min_dis_current = DistancePointToLine(multi_line_start[index], multi_line_start[index + 1], point); if (min_dis_current < min_dis) { min_dis = min_dis_current; } } if (isCloseCurve) { var min_dis_current = DistancePointToLine(multi_line_start[0], multi_line_start[multi_line_start.Count - 1], point); if (min_dis_current < min_dis) { min_dis = min_dis_current; } } return min_dis; } } }