예제 #1
0
        public static void ComputeCentroid(out Vec2 centroid, System.Collections.Generic.IList <Vec2> vertices)
        {
            if (!(vertices.Count >= 2))
            {
                throw new ArgumentOutOfRangeException("vertices");
            }

            centroid = Vec2.Empty;
            float area = 0.0f;

            if (vertices.Count == 2)
            {
                centroid = 0.5f * (vertices[0] + vertices[1]);
                return;
            }

            // pRef is the reference point for forming triangles.
            // It's location doesn't change the result (except for rounding error).
            Vec2 pRef = Vec2.Empty;

            const float inv3 = 1.0f / 3.0f;

            for (int i = 0; i < vertices.Count; ++i)
            {
                // Triangle vertices.
                Vec2 p1 = pRef;
                Vec2 p2 = vertices[i];
                Vec2 p3 = i + 1 < vertices.Count ? vertices[i + 1] : vertices[0];

                Vec2 e1 = p2 - p1;
                Vec2 e2 = p3 - p1;

                float D = e1.Cross(e2);

                float triangleArea = 0.5f * D;
                area += triangleArea;

                // Area weighted centroid
                centroid += triangleArea * inv3 * (p1 + p2 + p3);
            }

            // Centroid
            if (!(area > float.Epsilon))
            {
                throw new Exception("Area of polygon is too small");
            }

            centroid *= 1.0f / area;
        }
예제 #2
0
        public override void ComputeMass(out MassData massData, float density)
        {
            if (VertexCount < 2)
            {
                throw new ArgumentOutOfRangeException("Vertice count less than 2");
            }

            // A line segment has zero mass.
            if (VertexCount == 2)
            {
                massData = new MassData(0.0f,
                                        0.5f * (Vertices[0] + Vertices[1]),
                                        0.0f);
                return;
            }

            Vec2  center = Vec2.Empty;
            float area   = 0.0f;
            float I      = 0.0f;

            // pRef is the reference point for forming triangles.
            // It's location doesn't change the result (except for rounding error).
            Vec2 pRef = Vec2.Empty;

                #if NO
            // This code would put the reference point inside the polygon.
            for (int i = 0; i < VertexCount; ++i)
            {
                pRef += Vertices[i];
            }
            pRef *= 1.0f / count;
                #endif

            const float k_inv3 = 1.0f / 3.0f;

            for (int i = 0; i < VertexCount; ++i)
            {
                // Triangle vertices.
                Vec2 p1 = pRef;
                Vec2 p2 = Vertices[i];
                Vec2 p3 = i + 1 < VertexCount ? Vertices[i + 1] : Vertices[0];

                Vec2 e1 = p2 - p1;
                Vec2 e2 = p3 - p1;

                float D = e1.Cross(e2);

                float triangleArea = 0.5f * D;
                area += triangleArea;

                // Area weighted centroid
                center += triangleArea * k_inv3 * (p1 + p2 + p3);

                float px = p1.X, py = p1.Y;
                float ex1 = e1.X, ey1 = e1.Y;
                float ex2 = e2.X, ey2 = e2.Y;

                float intx2 = k_inv3 * (0.25f * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5f * px * px;
                float inty2 = k_inv3 * (0.25f * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5f * py * py;

                I += D * (intx2 + inty2);
            }

            if (!(area > float.Epsilon))
            {
                throw new Exception("Area is too small");
            }

            massData = new MassData(density * area,
                                    center * (1.0f / area),
                                    density * I);
        }
예제 #3
0
        void Set(Vec2[] verts)
        {
            Vec2[] normals = new Vec2[verts.Length];

            if (!(2 <= verts.Length && verts.Length <= Box2DSettings.b2_maxPolygonVertices))
            {
                throw new ArgumentOutOfRangeException("verts", "Vertice count is " + ((2 <= verts.Length) ? "less than 2" : "greater than " + Box2DSettings.b2_maxPolygonVertices.ToString()));
            }

            if (_autoReverse)
            // Ensure the polygon is convex and the interior
            // is to the left of each edge.
            {
                bool _reversed = false;
                for (int i = 0; i < verts.Length; ++i)
                {
                    int  i1   = i;
                    int  i2   = i + 1 < verts.Length ? i + 1 : 0;
                    Vec2 edge = verts[i2] - verts[i1];

                    for (int j = 0; j < verts.Length; ++j)
                    {
                        // Don't check vertices on the current edge.
                        if (j == i1 || j == i2)
                        {
                            continue;
                        }

                        Vec2 r = verts[j] - verts[i1];

                        // Your polygon is non-convex (it has an indentation) or
                        // has colinear edges.
                        float s = edge.Cross(r);
                        if (!(s > 0.0f))
                        {
                            _reversed = true;
                            verts     = ReverseOrder(verts);
                            break;
                        }
                    }

                    if (_reversed)
                    {
                        break;
                    }
                }
            }

            // Compute normals. Ensure the edges have non-zero length.
            for (int i = 0; i < verts.Length; ++i)
            {
                int  i1   = i;
                int  i2   = i + 1 < verts.Length ? i + 1 : 0;
                Vec2 edge = verts[i2] - verts[i1];

                if (!(edge.LengthSquared() > float.Epsilon * float.Epsilon))
                {
                    throw new Exception("Edge has a close-to-zero length (vertices too close?)");
                }

                normals[i] = edge.Cross(1.0f);
                normals[i].Normalize();
            }

            // Compute the polygon centroid.
            ComputeCentroid(out _internalPolyShape.m_centroid, verts);

            for (int i = 0; i < verts.Length; ++i)
            {
                _internalPolyShape.m_vertices[i] = verts[i];
                _internalPolyShape.m_normals[i]  = normals[i];
            }

            VertexCount = verts.Length;
        }