/// <summary> /// Determines if the specified polygon at the specified position and rotation contains the specified point /// </summary> /// <param name="poly">The polygon</param> /// <param name="pos">Origin of the polygon</param> /// <param name="rot">Rotation of the polygon</param> /// <param name="point">Point to check</param> /// <param name="strict">True if the edges do not count as inside</param> /// <returns>If the polygon at pos with rotation rot about its center contains point</returns> public static bool Contains(Polygon2 poly, Vector2 pos, Rotation2 rot, Vector2 point, bool strict) { if (!Rect2.Contains(poly.AABB, pos, point, strict)) { return(false); } // Calculate the area of the triangles constructed by the lines of the polygon. If it // matches the area of the polygon, we're inside the polygon. float myArea = 0; var center = poly.Center + pos; var last = Math2.Rotate(poly.Vertices[poly.Vertices.Length - 1], poly.Center, rot) + pos; for (int i = 0; i < poly.Vertices.Length; i++) { var curr = Math2.Rotate(poly.Vertices[i], poly.Center, rot) + pos; myArea += Math2.AreaOfTriangle(center, last, curr); last = curr; } return(Math2.Approximately(myArea, poly.Area, poly.Area / 1000)); }
/// <summary> /// Initializes a polygon with the specified vertices /// </summary> /// <param name="vertices">Vertices</param> /// <exception cref="ArgumentNullException">If vertices is null</exception> public Polygon2(Vector2[] vertices) { if (vertices == null) { throw new ArgumentNullException(nameof(vertices)); } Vertices = vertices; Normals = new List <Vector2>(); Vector2 tmp; for (int i = 1; i < vertices.Length; i++) { tmp = Math2.MakeStandardNormal(Vector2.Normalize(Math2.Perpendicular(vertices[i] - vertices[i - 1]))); if (!Normals.Contains(tmp)) { Normals.Add(tmp); } } tmp = Math2.MakeStandardNormal(Vector2.Normalize(Math2.Perpendicular(vertices[0] - vertices[vertices.Length - 1]))); if (!Normals.Contains(tmp)) { Normals.Add(tmp); } var min = new Vector2(vertices[0].X, vertices[0].Y); var max = new Vector2(min.X, min.Y); for (int i = 1; i < vertices.Length; i++) { min.X = Math.Min(min.X, vertices[i].X); min.Y = Math.Min(min.Y, vertices[i].Y); max.X = Math.Max(max.X, vertices[i].X); max.Y = Math.Max(max.Y, vertices[i].Y); } AABB = new Rect2(min, max); Center = new Vector2(0, 0); foreach (var vert in Vertices) { Center += vert; } Center *= (1.0f / Vertices.Length); // Find longest axis float longestAxisLenSq = -1; for (int i = 1; i < vertices.Length; i++) { var vec = vertices[i] - vertices[i - 1]; longestAxisLenSq = Math.Max(longestAxisLenSq, vec.LengthSquared()); } longestAxisLenSq = Math.Max(longestAxisLenSq, (vertices[0] - vertices[vertices.Length - 1]).LengthSquared()); LongestAxisLength = (float)Math.Sqrt(longestAxisLenSq); // Area and lines float area = 0; Lines = new Line2[Vertices.Length]; var last = Vertices[Vertices.Length - 1]; for (int i = 0; i < Vertices.Length; i++) { var next = Vertices[i]; Lines[i] = new Line2(last, next); area += Math2.AreaOfTriangle(last, next, Center); last = next; } Area = area; last = Vertices[Vertices.Length - 1]; var centToLast = (last - Center); var angLast = Math.Atan2(centToLast.Y, centToLast.X); var cwCounter = 0; var ccwCounter = 0; var foundDefinitiveResult = false; for (int i = 0; i < Vertices.Length; i++) { var curr = Vertices[i]; var centToCurr = (curr - Center); var angCurr = Math.Atan2(centToCurr.Y, centToCurr.X); var clockwise = angCurr < angLast; if (clockwise) { cwCounter++; } else { ccwCounter++; } Clockwise = clockwise; if (Math.Abs(angLast - angCurr) > Math2.DEFAULT_EPSILON) { foundDefinitiveResult = true; break; } last = curr; centToLast = centToCurr; angLast = angCurr; } if (!foundDefinitiveResult) { Clockwise = cwCounter > ccwCounter; } }