using RichCreator.Utility.Structs; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RichCreator.Utility.Utilitys { /// /// 几何体之间的关系类型 /// public enum Intersection { None,//没关系 Tangent,//切线,正切 Intersection,//相交,交叉 Containment//包含 } /// /// 与几何相关的辅助类 /// public static class GeometryHelper { /// /// 获取点到点的距离 /// /// /// /// public static double GetPointDistance(ZTPoint a, ZTPoint b) { return Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y)); } /// /// 获取点到直线的距离 /// /// /// /// public static double GetNearestDistance(ZTLinePoint line, ZTPoint point) { double a, b, c; a = GetPointDistance(line.P2, point); if (a <= 0.00001) { return 0.0f; } b = GetPointDistance(line.P1, point); if (b <= 0.00001) { return 0.0f; } c = GetPointDistance(line.P1, line.P2); if (c <= 0.00001) { //如果PA和PB坐标相同,则退出函数,并返回距离 return a; } if (a * a >= b * b + c * c) { return b; //如果是钝角返回b } if (b * b >= a * a + c * c) { return a; //如果是钝角返回a } double l = (a + b + c) / 2; //周长的一半 double s = Math.Sqrt(Math.Abs(l * (l - a) * (l - b) * (l - c))); //海伦公式求面积,也可以用矢量求 return 2 * s / c; } /// /// 判断线段与多边形的关系 /// /// /// /// public static Intersection IntersectionOf(ZTLinePoint line, ZTPolygon polygon) { if (polygon.Length == 0) { return Intersection.None; } if (polygon.Length == 1) { return IntersectionOf(polygon[0], line); } bool tangent = false; for (int index = 0; index < polygon.Length; index++) { int index2 = (index + 1) % polygon.Length; Intersection intersection = IntersectionOf(line, new ZTLinePoint(polygon[index], polygon[index2])); if (intersection == Intersection.Intersection) { return intersection; } if (intersection == Intersection.Tangent) { tangent = true; } } return tangent ? Intersection.Tangent : IntersectionOf(line.P1, polygon); } /// /// 判断点与多边形的关系 /// /// /// /// public static Intersection IntersectionOf(ZTPoint point, ZTPolygon polygon) { switch (polygon.Length) { case 0: return Intersection.None; case 1: if (polygon[0].X == point.X && polygon[0].Y == point.Y) { return Intersection.Tangent; } else { return Intersection.None; } case 2: return IntersectionOf(point, new ZTLinePoint(polygon[0], polygon[1])); } int counter = 0; int i; ZTPoint p1; int n = polygon.Length; p1 = polygon[0]; if (point .Equals( p1)) { return Intersection.Tangent; } for (i = 1; i <= n; i++) { ZTPoint p2 = polygon[i % n]; if (point .Equals( p2)) { return Intersection.Tangent; } if (point.Y > Math.Min(p1.Y, p2.Y)) { if (point.Y <= Math.Max(p1.Y, p2.Y)) { if (point.X <= Math.Max(p1.X, p2.X)) { if (p1.Y != p2.Y) { double xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X; if (p1.X == p2.X || point.X <= xinters) counter++; } } } } p1 = p2; } return (counter % 2 == 1) ? Intersection.Containment : Intersection.None; } /// /// 判断点与直线的关系 /// /// /// /// public static Intersection IntersectionOf(ZTPoint point, ZTLinePoint line) { float bottomY = Math.Min(line.Y1, line.Y2); float topY = Math.Max(line.Y1, line.Y2); bool heightIsRight = point.Y >= bottomY && point.Y <= topY; //Vertical line, slope is divideByZero error! if (line.X1 == line.X2) { if (point.X == line.X1 && heightIsRight) { return Intersection.Tangent; } else { return Intersection.None; } } float slope = (line.X2 - line.X1) / (line.Y2 - line.Y1); bool onLine = (line.Y1 - point.Y) == (slope * (line.X1 - point.X)); if (onLine && heightIsRight) { return Intersection.Tangent; } else { return Intersection.None; } } /// /// 判断直线与直线的关系 /// /// /// /// public static Intersection IntersectionOf(ZTLinePoint line1, ZTLinePoint line2) { // Fail if either line segment is zero-length. if (line1.X1 == line1.X2 && line1.Y1 == line1.Y2 || line2.X1 == line2.X2 && line2.Y1 == line2.Y2) return Intersection.None; if (line1.X1 == line2.X1 && line1.Y1 == line2.Y1 || line1.X2 == line2.X1 && line1.Y2 == line2.Y1) return Intersection.Intersection; if (line1.X1 == line2.X2 && line1.Y1 == line2.Y2 || line1.X2 == line2.X2 && line1.Y2 == line2.Y2) return Intersection.Intersection; // (1) Translate the system so that point A is on the origin. line1.X2 -= line1.X1; line1.Y2 -= line1.Y1; line2.X1 -= line1.X1; line2.Y1 -= line1.Y1; line2.X2 -= line1.X1; line2.Y2 -= line1.Y1; // Discover the length of segment A-B. double distAB = Math.Sqrt(line1.X2 * line1.X2 + line1.Y2 * line1.Y2); // (2) Rotate the system so that point B is on the positive X axis. double theCos = line1.X2 / distAB; double theSin = line1.Y2 / distAB; double newX = line2.X1 * theCos + line2.Y1 * theSin; line2.Y1 = (Int32)(line2.Y1 * theCos - line2.X1 * theSin); line2.X1 = (Int32)newX; newX = line2.X2 * theCos + line2.Y2 * theSin; line2.Y2 = (Int32)(line2.Y2 * theCos - line2.X2 * theSin); line2.X2 = (Int32)newX; // Fail if segment C-D doesn't cross line A-B. if (line2.Y1 < 0 && line2.Y2 < 0 || line2.Y1 >= 0 && line2.Y2 >= 0) return Intersection.None; // (3) Discover the position of the intersection point along line A-B. double posAB = line2.X2 + (line2.X1 - line2.X2) * line2.Y2 / (line2.Y2 - line2.Y1); // Fail if segment C-D crosses line A-B outside of segment A-B. if (posAB < 0 || posAB > distAB) return Intersection.None; // (4) Apply the discovered position to line A-B in the original coordinate system. return Intersection.Intersection; } } }