/// <summary> /// Determines if polygon 1 and polygon 2 at position 1 and position 2, respectively, intersect along axis. /// </summary> /// <param name="poly1">polygon 1</param> /// <param name="poly2">polygon 2</param> /// <param name="pos1">Origin of polygon 1</param> /// <param name="pos2">Origin of polygon 2</param> /// <param name="rot1">Rotation of the first polygon</param> /// <param name="rot2">Rotation of the second polygon</param> /// <param name="strict">If overlapping is required for intersection</param> /// <param name="axis">The axis to check</param> /// <returns>If poly1 at pos1 intersects poly2 at pos2 along axis</returns> public static bool IntersectsAlongAxis(Polygon2 poly1, Polygon2 poly2, Vector2 pos1, Vector2 pos2, Rotation2 rot1, Rotation2 rot2, bool strict, Vector2 axis) { var proj1 = ProjectAlongAxis(poly1, pos1, rot1, axis); var proj2 = ProjectAlongAxis(poly2, pos2, rot2, axis); return(AxisAlignedLine2.Intersects(proj1, proj2, strict)); }
/// <summary> /// Determines if the two polygons intersect using the Separating Axis Theorem. /// The performance of this function depends on the number of unique normals /// between the two polygons. /// </summary> /// <param name="poly1">First polygon</param> /// <param name="poly2">Second polygon</param> /// <param name="pos1">Offset for the vertices of the first polygon</param> /// <param name="pos2">Offset for the vertices of the second polygon</param> /// <param name="rot1">Rotation of the first polygon</param> /// <param name="rot2">Rotation of the second polygon</param> /// <param name="strict"> /// True if the two polygons must overlap a non-zero area for intersection, /// false if they must overlap on at least one point for intersection. /// </param> /// <returns>True if the polygons overlap, false if they do not</returns> public static bool IntersectsSat(Polygon2 poly1, Polygon2 poly2, Vector2 pos1, Vector2 pos2, Rotation2 rot1, Rotation2 rot2, bool strict) { if (rot1 == Rotation2.Zero && rot2 == Rotation2.Zero) { // This was a serious performance bottleneck so we speed up the fast case HashSet <Vector2> seen = new HashSet <Vector2>(); Vector2[] poly1Verts = poly1.Vertices; Vector2[] poly2Verts = poly2.Vertices; for (int i = 0, len = poly1.Normals.Count; i < len; i++) { var axis = poly1.Normals[i]; var proj1 = ProjectAlongAxis(axis, pos1, poly1Verts); var proj2 = ProjectAlongAxis(axis, pos2, poly2Verts); if (!AxisAlignedLine2.Intersects(proj1, proj2, strict)) { return(false); } seen.Add(axis); } for (int i = 0, len = poly2.Normals.Count; i < len; i++) { var axis = poly2.Normals[i]; if (seen.Contains(axis)) { continue; } var proj1 = ProjectAlongAxis(axis, pos1, poly1Verts); var proj2 = ProjectAlongAxis(axis, pos2, poly2Verts); if (!AxisAlignedLine2.Intersects(proj1, proj2, strict)) { return(false); } } return(true); } foreach (var norm in poly1.Normals.Select((v) => Tuple.Create(v, rot1)).Union(poly2.Normals.Select((v) => Tuple.Create(v, rot2)))) { var axis = Math2.Rotate(norm.Item1, Vector2.Zero, norm.Item2); if (!IntersectsAlongAxis(poly1, poly2, pos1, pos2, rot1, rot2, strict, axis)) { return(false); } } return(true); }
/// <summary> /// Determines if box1 with origin pos1 intersects box2 with origin pos2. /// </summary> /// <param name="box1">Box 1</param> /// <param name="box2">Box 2</param> /// <param name="pos1">Origin of box 1</param> /// <param name="pos2">Origin of box 2</param> /// <param name="strict">If overlap is required for intersection</param> /// <returns>If box1 intersects box2 when box1 is at pos1 and box2 is at pos2</returns> public static bool Intersects(Rect2 box1, Rect2 box2, Vector2 pos1, Vector2 pos2, bool strict) { return(AxisAlignedLine2.Intersects(box1.Min.X + pos1.X, box1.Max.X + pos1.X, box2.Min.X + pos2.X, box2.Max.X + pos2.X, strict, false) && AxisAlignedLine2.Intersects(box1.Min.Y + pos1.Y, box1.Max.Y + pos1.Y, box2.Min.Y + pos2.Y, box2.Max.Y + pos2.Y, strict, false)); }
/// <summary> /// Determines if line1 intersects line2, when line1 is offset by pos1 and line2 /// is offset by pos2. /// </summary> /// <param name="line1">Line 1</param> /// <param name="line2">Line 2</param> /// <param name="pos1">Origin of line 1</param> /// <param name="pos2">Origin of line 2</param> /// <param name="strict">If overlap is required for intersection</param> /// <returns>If line1 intersects line2</returns> public static bool Intersects(Line2 line1, Line2 line2, Vector2 pos1, Vector2 pos2, bool strict) { if (line1.Horizontal && line2.Horizontal) { return(AxisAlignedLine2.Intersects(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.MinX + pos2.X, line2.MaxX + pos2.X, strict, false)); } else if (line1.Vertical && line2.Vertical) { return(AxisAlignedLine2.Intersects(line1.MinY + pos1.Y, line1.MaxY + pos1.Y, line2.MinY + pos2.Y, line2.MaxY + pos2.Y, strict, false)); } else if (line1.Horizontal || line2.Horizontal) { if (line2.Horizontal) { // swap line 1 and 2 to prevent duplicating everything var tmp = line1; var tmpp = pos1; line1 = line2; pos1 = pos2; line2 = tmp; pos2 = tmpp; } if (line2.Vertical) { return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.Start.X + pos2.X, strict, false) && AxisAlignedLine2.Contains(line2.MinY + pos2.Y, line2.MaxY + pos2.Y, line1.Start.Y + pos1.Y, strict, false)); } else { // recalculate line2 y intercept // y = mx + b // b = y - mx var line2YIntInner = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X); // check line2.x at line1.y // line2.y = line2.slope * line2.x + line2.yintercept // line1.y = line2.slope * line2.x + line2.yintercept // line1.y - line2.yintercept = line2.slope * line2.x // (line1.y - line2.yintercept) / line2.slope = line2.x var line2XAtLine1Y = (line1.Start.Y + pos1.Y - line2YIntInner) / line2.Slope; return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2XAtLine1Y, strict, false) && AxisAlignedLine2.Contains(line2.MinX + pos2.X, line2.MaxX + pos2.X, line2XAtLine1Y, strict, false)); } } else if (line1.Vertical) { // vertical line with regular line var line2YIntInner = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X); var line2YAtLine1X = line2.Slope * (line1.Start.X + pos1.X) + line2YIntInner; return(AxisAlignedLine2.Contains(line1.MinY + pos1.Y, line1.MaxY + pos1.Y, line2YAtLine1X, strict, false) && AxisAlignedLine2.Contains(line2.MinY + pos2.Y, line2.MaxY + pos2.Y, line2YAtLine1X, strict, false)); } // two non-vertical, non-horizontal lines var line1YInt = line1.Start.Y + pos1.Y - line1.Slope * (line1.Start.X + pos1.X); var line2YInt = line2.Start.Y + pos2.Y - line2.Slope * (line2.Start.X + pos2.X); if (Math.Abs(line1.Slope - line2.Slope) <= Math2.DEFAULT_EPSILON) { // parallel lines if (line1YInt != line2YInt) { return(false); // infinite lines don't intersect } // parallel lines with equal y intercept. Intersect if ever at same X coordinate. return(AxisAlignedLine2.Intersects(line1.MinX + pos1.X, line1.MaxX + pos1.X, line2.MinX + pos2.X, line2.MaxX + pos2.X, strict, false)); } else { // two non-parallel lines. Only one possible intersection point // y1 = y2 // line1.Slope * x + line1.YIntercept = line2.Slope * x + line2.YIntercept // line1.Slope * x - line2.Slope * x = line2.YIntercept - line1.YIntercept // x (line1.Slope - line2.Slope) = line2.YIntercept - line1.YIntercept // x = (line2.YIntercept - line1.YIntercept) / (line1.Slope - line2.Slope) var x = (line2YInt - line1YInt) / (line1.Slope - line2.Slope); return(AxisAlignedLine2.Contains(line1.MinX + pos1.X, line1.MaxX + pos1.X, x, strict, false) && AxisAlignedLine2.Contains(line2.MinX + pos1.X, line2.MaxX + pos2.X, x, strict, false)); } }