using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CommonLang.Geometry { /// /// A code container for collision-related mathematical functions. /// static public class CollisionMath { /// /// Data defining a circle/line collision result. /// /// Also used for circle/rectangles. public struct CircleLineCollisionResult { public bool Collision; public Vector2 Point; public Vector2 Normal; public float Distance; } /// /// Determine if two circles intersect or contain each other. /// /// The center of the first circle. /// The radius of the first circle. /// The center of the second circle. /// The radius of the second circle. /// True if the circles intersect or contain one another. public static bool CircleCircleIntersect(Vector2 center1, float radius1, Vector2 center2, float radius2) { Vector2 line = center2 - center1; // we use LengthSquared to avoid a costly square-root call return (line.LengthSquared() <= (radius1 + radius2) * (radius1 + radius2)); } /// /// Determines the point of intersection between two line segments, /// as defined by four points. /// /// The first point on the first line segment. /// The second point on the first line segment. /// The first point on the second line segment. /// The second point on the second line segment. /// The output value with the interesection, if any. /// The output parameter "point" is only valid /// when the return value is true. /// True if intersecting, false otherwise. public static bool LineLineIntersect(Vector2 a, Vector2 b, Vector2 c, Vector2 d, out Vector2 point) { point = Vector2.Zero; double r, s; double denominator = (b.X - a.X) * (d.Y - c.Y) - (b.Y - a.Y) * (d.X - c.X); // If the denominator in above is zero, AB & CD are colinear if (denominator == 0) { return false; } double numeratorR = (a.Y - c.Y) * (d.X - c.X) - (a.X - c.X) * (d.Y - c.Y); r = numeratorR / denominator; double numeratorS = (a.Y - c.Y) * (b.X - a.X) - (a.X - c.X) * (b.Y - a.Y); s = numeratorS / denominator; // non-intersecting if (r < 0 || r > 1 || s < 0 || s > 1) { return false; } // find intersection point point.X = (float)(a.X + (r * (b.X - a.X))); point.Y = (float)(a.Y + (r * (b.Y - a.Y))); return true; } public static bool LineLineIntersect(Vector2 a, Vector2 b, Vector2 c, Vector2 d) { double r, s; double denominator = (b.X - a.X) * (d.Y - c.Y) - (b.Y - a.Y) * (d.X - c.X); // If the denominator in above is zero, AB & CD are colinear if (denominator == 0) { return false; } double numeratorR = (a.Y - c.Y) * (d.X - c.X) - (a.X - c.X) * (d.Y - c.Y); r = numeratorR / denominator; double numeratorS = (a.Y - c.Y) * (b.X - a.X) - (a.X - c.X) * (b.Y - a.Y); s = numeratorS / denominator; // non-intersecting if (r < 0 || r > 1 || s < 0 || s > 1) { return false; } return true; } /// /// Determines if a circle and line segment intersect, and if so, how they do. /// /// The center of the circle. /// The radius of the circle. /// The first point on the line segment. /// The second point on the line segment. /// The result data for the collision. /// True if a collision occurs, provided for convenience. public static bool CircleLineCollide(Vector2 center, float radius, Vector2 lineStart, Vector2 lineEnd, ref CircleLineCollisionResult result) { Vector2 AC = center - lineStart; Vector2 AB = lineEnd - lineStart; float ab2 = AB.LengthSquared(); if (ab2 <= 0f) { return false; } float acab = Vector2.Dot(AC, AB); float t = acab / ab2; if (t < 0.0f) t = 0.0f; else if (t > 1.0f) t = 1.0f; result.Point = lineStart + t * AB; result.Normal = center - result.Point; float h2 = result.Normal.LengthSquared(); float r2 = radius * radius; if ((h2 == 0) || (h2 <= r2)) { result.Normal.Normalize(); result.Distance = (radius - (center - result.Point).Length()); result.Collision = true; } else { result.Collision = false; } return result.Collision; } public static bool CircleLineCollide(Vector2 center, float radius, Vector2 lineStart, Vector2 lineEnd) { Vector2 AC = center - lineStart; Vector2 AB = lineEnd - lineStart; float ab2 = AB.LengthSquared(); if (ab2 <= 0f) { return false; } float acab = Vector2.Dot(AC, AB); float t = acab / ab2; if (t < 0.0f) t = 0.0f; else if (t > 1.0f) t = 1.0f; Vector2 resultPoint = lineStart + t * AB; Vector2 resultNormal = center - resultPoint; float h2 = resultNormal.LengthSquared(); float r2 = radius * radius; if ((h2 == 0) || (h2 <= r2)) { return true; } else { return false; } } /// /// 点在凸多边形内部。 /// /// /// /// public static bool PointInPolygon(Vector2 center, Vector2[] list) { int wn = 0, j = 0; //wn 计数器 j第二个 for (int i = 0; i < list.Length; i++) { //开始循环 if (i == list.Length - 1) { j = 0;//如果 循环到最后一点 第二个指针指向第一点 } else { j = j + 1; //如果不是 ,则找下一点 } if (list[i].Y <= center.Y) // 如果多边形的点 小于等于 选定点的 Y 坐标 { if (list[j].Y > center.Y) // 如果多边形的下一点 大于于 选定点的 Y 坐标 { if (isLeft(list[i], list[j], center) > 0) { wn++; } } } else { if (list[j].Y <= center.Y) { if (isLeft(list[i], list[j], center) < 0) { wn--; } } } } if (wn == 0) { return false; } else { return true; } } //判断点在线的一边 public static float isLeft(Vector2 P0, Vector2 P1, Vector2 P2) { float abc = ((P1.X - P0.X) * (P2.Y - P0.Y) - (P2.X - P0.X) * (P1.Y - P0.Y)); return abc; } public static Vector2 MoveToByRadians(Vector2 p, float degree, float distance) { return new Vector2( p.X + (float)(Math.Cos(degree) * distance), p.Y + (float)(Math.Sin(degree) * distance)); } } }