/// <summary> /// Checks if this triangle contains the given point. This is /// never strict. /// </summary> /// <param name="tri">The triangle</param> /// <param name="pos">The position of the triangle</param> /// <param name="pt">The point to check</param> /// <returns>true if this triangle contains the point or the point /// is along an edge of this polygon</returns> public static bool Contains(Triangle2 tri, Vector2 pos, Vector2 pt) { Vector2 relPt = pt - pos - tri.Vertices[0]; float r = tri.InvContainsBasis[0] * relPt.X + tri.InvContainsBasis[1] * relPt.Y; if (r < -Math2.DEFAULT_EPSILON) { return(false); } float t = tri.InvContainsBasis[2] * relPt.X + tri.InvContainsBasis[3] * relPt.Y; if (t < -Math2.DEFAULT_EPSILON) { return(false); } return((r + t) < 1 + Math2.DEFAULT_EPSILON); }
/// <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) { // The point is contained in the polygon iff it is contained in one of the triangles // which partition this polygon. Due to how we constructed the triangles, it will // be on the edge of the polygon if its on the first 2 edges of the triangle. for (int i = 0, len = poly.TrianglePartition.Length; i < len; i++) { var tri = poly.TrianglePartition[i]; if (Triangle2.Contains(tri, pos, point)) { if (strict && (Line2.Contains(tri.Edges[0], pos, point) || Line2.Contains(tri.Edges[1], pos, point))) { return(false); } return(true); } } return(false); }
/// <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) { Vertices = vertices ?? throw new ArgumentNullException(nameof(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); _LongestAxisLength = -1; // Center, area, and lines TrianglePartition = new Triangle2[Vertices.Length - 2]; float[] triangleSortKeys = new float[TrianglePartition.Length]; float area = 0; Lines = new Line2[Vertices.Length]; Lines[0] = new Line2(Vertices[Vertices.Length - 1], Vertices[0]); var last = Vertices[0]; Center = new Vector2(0, 0); for (int i = 1; i < Vertices.Length - 1; i++) { var next = Vertices[i]; var next2 = Vertices[i + 1]; Lines[i] = new Line2(last, next); var tri = new Triangle2(new Vector2[] { Vertices[0], next, next2 }); TrianglePartition[i - 1] = tri; triangleSortKeys[i - 1] = -tri.Area; area += tri.Area; Center += tri.Center * tri.Area; last = next; } Lines[Vertices.Length - 1] = new Line2(Vertices[Vertices.Length - 2], Vertices[Vertices.Length - 1]); Array.Sort(triangleSortKeys, TrianglePartition); Area = area; Center /= area; last = Vertices[Vertices.Length - 1]; var centToLast = (last - Center); var angLast = Rotation2.Standardize((float)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 = Rotation2.Standardize((float)Math.Atan2(centToCurr.Y, centToCurr.X)); var clockwise = (angCurr < angLast && (angCurr - angLast) < Math.PI) || (angCurr - angLast) > Math.PI; 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; } }