// From Eric Jordan's convex decomposition library /// <summary> /// Checks if polygon is valid for use in Box2d engine. /// Last ditch effort to ensure no invalid polygons are /// added to world geometry. /// /// Performs a full check, for simplicity, convexity, /// orientation, minimum angle, and volume. This won't /// be very efficient, and a lot of it is redundant when /// other tools in this section are used. /// </summary> /// <returns></returns> public bool CheckPolygon() { int error = -1; if (Count < 3 || Count > Settings.MaxPolygonVertices) { error = 0; } if (!IsConvex()) { error = 1; } if (!IsSimple()) { error = 2; } if (GetArea() < Settings.Epsilon) { error = 3; } //Compute normals Vector2[] normals = new Vector2[Count]; Vertices vertices = new Vertices(Count); for (int i = 0; i < Count; ++i) { vertices.Add(new Vector2(this[i].X, this[i].Y)); int i1 = i; int i2 = i + 1 < Count ? i + 1 : 0; Vector2 edge = new Vector2(this[i2].X - this[i1].X, this[i2].Y - this[i1].Y); normals[i] = MathUtils.Cross(edge, 1.0f); normals[i].Normalize(); } //Required side checks for (int i = 0; i < Count; ++i) { int iminus = (i == 0) ? Count - 1 : i - 1; //Parallel sides check float cross = MathUtils.Cross(normals[iminus], normals[i]); cross = MathUtils.Clamp(cross, -1.0f, 1.0f); float angle = ( float )Math.Asin(cross); if (angle <= Settings.AngularSlop) { error = 4; break; } //Too skinny check for (int j = 0; j < Count; ++j) { if (j == i || j == (i + 1) % Count) { continue; } float s = Vector2.Dot(normals[i], vertices[j] - vertices[i]); if (s >= -Settings.LinearSlop) { error = 5; } } Vector2 centroid = vertices.GetCentroid(); Vector2 n1 = normals[iminus]; Vector2 n2 = normals[i]; Vector2 v = vertices[i] - centroid; Vector2 d = new Vector2(); d.X = Vector2.Dot(n1, v); // - toiSlop; d.Y = Vector2.Dot(n2, v); // - toiSlop; // Shifting the edge inward by toiSlop should // not cause the plane to pass the centroid. if ((d.X < 0.0f) || (d.Y < 0.0f)) { error = 6; } } if (error != -1) { Debug.WriteLine("Found invalid polygon, "); switch (error) { case 0: Debug.WriteLine(string.Format("must have between 3 and {0} vertices.\n", Settings.MaxPolygonVertices)); break; case 1: Debug.WriteLine("must be convex.\n"); break; case 2: Debug.WriteLine("must be simple (cannot intersect itself).\n"); break; case 3: Debug.WriteLine("area is too small.\n"); break; case 4: Debug.WriteLine("sides are too close to parallel.\n"); break; case 5: Debug.WriteLine("polygon is too thin.\n"); break; case 6: Debug.WriteLine("core shape generation would move edge past centroid (too thin).\n"); break; default: Debug.WriteLine("don't know why.\n"); break; } } return(error != -1); }
// From Eric Jordan's convex decomposition library /// <summary> /// Checks if polygon is valid for use in Box2d engine. /// Last ditch effort to ensure no invalid polygons are /// added to world geometry. /// /// Performs a full check, for simplicity, convexity, /// orientation, minimum angle, and volume. This won't /// be very efficient, and a lot of it is redundant when /// other tools in this section are used. /// </summary> /// <returns></returns> public bool CheckPolygon(out int error, out string errorMessage) { error = -1; errorMessage = null; if (Count < 3 || Count > Settings.MaxPolygonVertices) { error = 0; } if (!IsConvex()) { error = 1; } if (!IsSimple()) { error = 2; } if (GetArea() < Settings.Epsilon) { error = 3; } //Compute normals Vector2[] normals = new Vector2[Count]; Vertices vertices = new Vertices(Count); for (int i = 0; i < Count; ++i) { vertices.Add(new Vector2(this[i].x, this[i].y)); int i1 = i; int i2 = i + 1 < Count ? i + 1 : 0; Vector2 edge = new Vector2(this[i2].x - this[i1].x, this[i2].y - this[i1].y); normals[i] = MathUtils.Cross(edge, 1.0f); normals[i].Normalize(); } //Required side checks for (int i = 0; i < Count; ++i) { int iminus = (i == 0) ? Count - 1 : i - 1; //Parallel sides check float cross = MathUtils.Cross(normals[iminus], normals[i]); cross = MathUtils.Clamp(cross, -1.0f, 1.0f); float angle = Mathf.Asin(cross); if (angle <= Settings.AngularSlop) { error = 4; break; } //Too skinny check for (int j = 0; j < Count; ++j) { if (j == i || j == (i + 1) % Count) { continue; } float s = Vector2.Dot(normals[i], vertices[j] - vertices[i]); if (s >= -Settings.LinearSlop) { error = 5; } } Vector2 centroid = vertices.GetCentroid(); Vector2 n1 = normals[iminus]; Vector2 n2 = normals[i]; Vector2 v = vertices[i] - centroid; Vector2 d = new Vector2(); d.x = Vector2.Dot(n1, v); // - toiSlop; d.y = Vector2.Dot(n2, v); // - toiSlop; // Shifting the edge inward by toiSlop should // not cause the plane to pass the centroid. if ((d.x < 0.0f) || (d.y < 0.0f)) { error = 6; } } if (error != -1) { switch (error) { case 0: errorMessage = string.Format("Polygon error: must have between 3 and {0} vertices.", Settings.MaxPolygonVertices); break; case 1: errorMessage = "Polygon error: must be convex."; break; case 2: errorMessage = "Polygon error: must be simple (cannot intersect itself)."; break; case 3: errorMessage = "Polygon error: area is too small."; break; case 4: errorMessage = "Polygon error: sides are too close to parallel."; break; case 5: errorMessage = "Polygon error: polygon is too thin."; break; case 6: errorMessage = "Polygon error: core shape generation would move edge past centroid (too thin)."; break; default: errorMessage = "Polygon error: error " + error.ToString(); break; } } return(error != -1); }