// Check if polygon A is going to collide with polygon B for the given velocity public SvgCollision.PolygonCollisionResult PolygonCollision(Polygon polygonA, Polygon polygonB, Vector velocity) { SvgCollision.PolygonCollisionResult result = new SvgCollision.PolygonCollisionResult(); result.IsIntersecting = true; result.WillIntersect = true; int edgeCountA = polygonA.Edges.Count; int edgeCountB = polygonB.Edges.Count; float minIntervalDistance = float.PositiveInfinity; Vector translationAxis = new Vector(); Vector edge; // Loop through all the edges of both polygons for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) { if (edgeIndex < edgeCountA) { edge = polygonA.Edges[edgeIndex]; } else { edge = polygonB.Edges[edgeIndex - edgeCountA]; } // ===== 1. Find if the polygons are currently intersecting ===== // Find the axis perpendicular to the current edge Vector axis = new Vector(-edge.Y, edge.X); axis.Normalize(); // Find the projection of the polygon on the current axis float minA = 0; float minB = 0; float maxA = 0; float maxB = 0; ProjectPolygon(axis, polygonA, ref minA, ref maxA); ProjectPolygon(axis, polygonB, ref minB, ref maxB); // Check if the polygon projections are currentlty intersecting float intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) result.IsIntersecting = false; // ===== 2. Now find if the polygons *will* intersect ===== // Project the velocity on the current axis float velocityProjection = axis.DotProduct(velocity); // Get the projection of polygon A during the movement if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // Do the same test as above for the new projection intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) result.WillIntersect = false; // If the polygons are not intersecting and won't intersect, exit the loop if (!result.IsIntersecting && !result.WillIntersect) break; // Check if the current interval distance is the minimum one. If so store // the interval distance and the current distance. // This will be used to calculate the minimum translation vector intervalDistance = Math.Abs(intervalDistance); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; translationAxis = axis; Vector d = polygonA.Center - polygonB.Center; if (d.DotProduct(translationAxis) < 0) translationAxis = -translationAxis; } } // The minimum translation vector can be used to push the polygons appart. // First moves the polygons by their velocity // then move polygonA by MinimumTranslationVector. if (result.WillIntersect) result.MinimumTranslationVector = translationAxis * minIntervalDistance; return result; }
/// <summary> /// Test if two polygons collide by testing each line segment in polygon 1 against each line segment in polygon 2. /// Returns a parially filled SvgCollision.PolygonCollisionResult. /// </summary> /// <param name="ptsA">Polygon 1 point array</param> /// <param name="ptsB">Polygon 2 point array</param> /// <returns></returns> public static SvgCollision.PolygonCollisionResult PolygonCollision(PointF[] ptsA, PointF[] ptsB) { SvgCollision.PolygonCollisionResult result = new SvgCollision.PolygonCollisionResult(); result.LineIntersectingPoints = new List<PointF>(); PointF previousA = new PointF(); PointF previousB = new PointF(); foreach (PointF ptsa in ptsA) { if (!(previousA.IsEmpty)) { foreach (PointF ptsb in ptsB) { if (!(previousB.IsEmpty)) { if (ptsa != ptsb && previousA != previousB) { bool blurp = DoLinesIntersect(previousA, ptsa, previousB, ptsb); if (blurp) { result.IsIntersecting = true; result.OnPath = true; PointF intersection; LineIntersectionPoint(ptsa, previousA, ptsb, previousB, out intersection); result.LineIntersectingPoints.Add(intersection); } } } previousB = ptsb; } previousB = new PointF(); } previousA = ptsa; } return result; }