public static bool TestRayPolygon(LVector2 o, LVector2 dir, LVector2 *points, int vertexCount, ref LVector2 point) { LFloat t = LFloat.FLT_MAX; for (var i = 0; i < vertexCount; i++) { var b1 = points[i]; var b2 = points[(i + 1) % vertexCount]; var inter = TestRaySegment(o, dir, b1, b2); if (inter >= 0) { if (inter < t) { t = inter; } } } if (t < LFloat.FLT_MAX) { point = o + dir * t; } return(false); }
/// <summary> /// 射线和多边形 /// </summary> /// <param name="o"></param> /// <param name="dir"></param> /// <param name="points"></param> /// <param name="vertexCount"></param> /// <returns></returns> public static bool TestRayPolygon(LVector2 o, LVector2 dir, LVector2 *points, int vertexCount) { for (int i = 0; i < vertexCount; i++) { LVector2 b1 = points[i]; LVector2 b2 = points[(i + 1) % vertexCount]; int inter = TestRaySegment(o, dir, b1, b2); if (inter >= 0) { return(true); } } return(false); }
//http://www.kevlindev.com/geometry/2D/intersections/index.htm //http://www.kevlindev.com/geometry/2D/intersections/index.htm //https://bitlush.com/blog/circle-vs-polygon-collision-detection-in-c-sharp public static bool TestCirclePolygon(LVector2 c, LFloat r, LVector2 *_points, int vertexCount) { var radiusSquared = r * r; var circleCenter = c; var nearestDistance = LFloat.MaxValue; int nearestVertex = -1; for (var i = 0; i < vertexCount; i++) { LVector2 axis = circleCenter - _points[i]; var distance = axis.sqrMagnitude - radiusSquared; if (distance <= 0) { return(true); } if (distance < nearestDistance) { nearestVertex = i; nearestDistance = distance; } } LVector2 GetPoint(int index) { if (index < 0) { index += vertexCount; } else if (index >= vertexCount) { index -= vertexCount; } return(_points[index]); } var vertex = GetPoint(nearestVertex - 1); for (var i = 0; i < 2; i++) { var nextVertex = GetPoint(nearestVertex + i); var edge = nextVertex - vertex; var edgeLengthSquared = edge.sqrMagnitude; if (edgeLengthSquared != 0) { LVector2 axis = circleCenter - vertex; var dot = LVector2.Dot(edge, axis); if (dot >= 0 && dot <= edgeLengthSquared) { LVector2 projection = vertex + (dot / edgeLengthSquared) * edge; axis = projection - circleCenter; if (axis.sqrMagnitude <= radiusSquared) { return(true); } else { if (edge.x > 0) { if (axis.y > 0) { return(false); } } else if (edge.x < 0) { if (axis.y < 0) { return(false); } } else if (edge.y > 0) { if (axis.x < 0) { return(false); } } else { if (axis.x > 0) { return(false); } } } } } vertex = nextVertex; } return(true); }
//TODO public static bool TestPolygonPolygon(LVector2 *_points, int vertexCount, LVector2 *_points2, int vertexCount2) { return(false); }
/// <summary> /// 测试圆和多边形是否相交 /// </summary> /// <param name="c"></param> /// <param name="r"></param> /// <param name="_points"></param> /// <param name="vertextCount">多边形顶点数量</param> /// <returns></returns> public static bool TestCirclePolygon(LVector2 c, LFloat r, LVector2 *_points, int vertextCount) { //圆形的半径平方 var radiusSquared = r * r; //圆的中心点 var circleCenter = c; // 记录最近的距离 var nearestDistance = LFloat.MaxValue; // 记录最近的顶点 int nearestVertex = -1; for (int i = 0; i < vertextCount; i++) { LVector2 axix = circleCenter - _points[i]; // 多边形的任何顶点在圆的范围内 说明相交 var distance = axix.sqrMagnitude - radiusSquared; if (distance <= 0) { return(true); } if (distance < nearestDistance) { nearestVertex = i; nearestDistance = distance; } } // 获取点 LVector2 GetPoint(int index) { if (index < 0) { index += vertextCount; } else if (index >= vertextCount) { index -= vertextCount; } return(_points[index]); } var vertex = GetPoint(nearestVertex - 1); for (int i = 0; i < 2; i++) { LVector2 nextVertex = GetPoint(nearestVertex + 1); LVector2 edge = nextVertex - vertex; LFloat edgeLengthSquared = edge.sqrMagnitude; if (edgeLengthSquared != 0) { LVector2 axis = circleCenter - vertex; LFloat dot = LVector2.Dot(edge, axis); if (dot >= 0 && dot <= edgeLengthSquared) { // (dot / edgeLengthSquare ) * edge 是求 向量的投影 // 两向量 a' b' 夹角β // a·b = |a'||b'|cosβ // LVector2 projection = vertex + (dot / edgeLengthSquared) * edge; axis = projection - circleCenter; if (axis.sqrMagnitude <= radiusSquared) { return(true); } else { if (edge.x > 0) { if (axis.y > 0) { return(false); } else if (edge.x < 0) { if (axis.y < 0) { return(false); } else if (edge.y > 0) { if (axis.x < 0) { return(false); } else if (axis.x > 0) { return(false); } } } } } } } vertex = nextVertex; } return(true); }