/// <summary> /// Create a convex hull from the given array of points. /// The count must be in the range [3, Settings.maxPolygonVertices]. /// This method takes an arraypool for pooling /// </summary> /// <warning>the points may be re-ordered, even if they form a convex polygon</warning> /// <warning>collinear points are handled but not removed. Collinear points may lead to poor stacking behavior.</warning> public void Set(Vec2[] verts, int num, Vec2Array vecPool, IntArray intPool) { Debug.Assert(3 <= num && num <= Settings.MAX_POLYGON_VERTICES); if (num < 3) { SetAsBox(1.0f, 1.0f); return; } int n = MathUtils.Min(num, Settings.MAX_POLYGON_VERTICES); // Copy the vertices into a local buffer Vec2[] ps = (vecPool != null) ? vecPool.Get(n) : new Vec2[n]; for (int i = 0; i < n; ++i) { ps[i] = verts[i]; } // Create the convex hull using the Gift wrapping algorithm // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm // Find the right most point on the hull int i0 = 0; float x0 = ps[0].X; for (int i = 1; i < num; ++i) { float x = ps[i].X; if (x > x0 || (x == x0 && ps[i].Y < ps[i0].Y)) { i0 = i; x0 = x; } } int[] hull = (intPool != null) ? intPool.Get(Settings.MAX_POLYGON_VERTICES) : new int[Settings.MAX_POLYGON_VERTICES]; int m = 0; int ih = i0; while (true) { hull[m] = ih; int ie = 0; for (int j = 1; j < n; ++j) { if (ie == ih) { ie = j; continue; } Vec2 r = pool1.Set(ps[ie]).SubLocal(ps[hull[m]]); Vec2 v = pool2.Set(ps[j]).SubLocal(ps[hull[m]]); float c = Vec2.Cross(r, v); if (c < 0.0f) { ie = j; } // Collinearity check if (c == 0.0f && v.LengthSquared() > r.LengthSquared()) { ie = j; } } ++m; ih = ie; if (ie == i0) { break; } } VertexCount = m; // Copy vertices. for (int i = 0; i < VertexCount; ++i) { if (Vertices[i] == null) { Vertices[i] = new Vec2(); } Vertices[i].Set(ps[hull[i]]); } Vec2 edge = pool1; // Compute normals. Ensure the edges have non-zero length. for (int i = 0; i < VertexCount; ++i) { int i1 = i; int i2 = i + 1 < VertexCount ? i + 1 : 0; edge.Set(Vertices[i2]).SubLocal(Vertices[i1]); Debug.Assert(edge.LengthSquared() > Settings.EPSILON * Settings.EPSILON); Vec2.CrossToOutUnsafe(edge, 1f, Normals[i]); Normals[i].Normalize(); } // Compute the polygon centroid. ComputeCentroidToOut(Vertices, VertexCount, Centroid); }
/// <summary> /// Create a convex hull from the given array of points. /// The count must be in the range [3, Settings.maxPolygonVertices]. /// This method takes an arraypool for pooling /// </summary> /// <warning>the points may be re-ordered, even if they form a convex polygon</warning> /// <warning>collinear points are handled but not removed. Collinear points may lead to poor stacking behavior.</warning> public void set_Renamed(Vec2[] verts, int num, Vec2Array vecPool, IntArray intPool) { Debug.Assert(3 <= num && num <= Settings.maxPolygonVertices); if (num < 3) { setAsBox(1.0f, 1.0f); return; } int n = MathUtils.min(num, Settings.maxPolygonVertices); // Copy the vertices into a local buffer Vec2[] ps = (vecPool != null) ? vecPool.get_Renamed(n) : new Vec2[n]; for (int i = 0; i < n; ++i) { ps[i] = verts[i]; } // Create the convex hull using the Gift wrapping algorithm // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm // Find the right most point on the hull int i0 = 0; float x0 = ps[0].x; for (int i = 1; i < num; ++i) { float x = ps[i].x; if (x > x0 || (x == x0 && ps[i].y < ps[i0].y)) { i0 = i; x0 = x; } } int[] hull = (intPool != null) ? intPool.get_Renamed(Settings.maxPolygonVertices) : new int[Settings.maxPolygonVertices]; int m = 0; int ih = i0; while (true) { hull[m] = ih; int ie = 0; for (int j = 1; j < n; ++j) { if (ie == ih) { ie = j; continue; } Vec2 r = pool1.set_Renamed(ps[ie]).subLocal(ps[hull[m]]); Vec2 v = pool2.set_Renamed(ps[j]).subLocal(ps[hull[m]]); float c = Vec2.cross(r, v); if (c < 0.0f) { ie = j; } // Collinearity check if (c == 0.0f && v.lengthSquared() > r.lengthSquared()) { ie = j; } } ++m; ih = ie; if (ie == i0) { break; } } this.m_count = m; // Copy vertices. for (int i = 0; i < m_count; ++i) { if (m_vertices[i] == null) { m_vertices[i] = new Vec2(); } m_vertices[i].set_Renamed(ps[hull[i]]); } Vec2 edge = pool1; // Compute normals. Ensure the edges have non-zero length. for (int i = 0; i < m_count; ++i) { int i1 = i; int i2 = i + 1 < m_count ? i + 1 : 0; edge.set_Renamed(m_vertices[i2]).subLocal(m_vertices[i1]); Debug.Assert(edge.lengthSquared() > Settings.EPSILON * Settings.EPSILON); Vec2.crossToOutUnsafe(edge, 1f, m_normals[i]); m_normals[i].normalize(); } // Compute the polygon centroid. computeCentroidToOut(m_vertices, m_count, m_centroid); }