예제 #1
0
        /// <summary>
        /// Returns the entries of the cotangent-weighted Laplacian matrix in row-major order.
        /// Based on symmetric derivation of the Laplace-Beltrami operator detailed in http://www.cs.jhu.edu/~misha/ReadingSeminar/Papers/Vallet08.pdf.
        /// Also returns the barycentric dual area of each vertex.
        /// Assumes triangle mesh.
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="entriesOut"></param>
        /// <param name="areasOut"></param>
        public static void GetLaplacianMatrix(this Mesh mesh, double[] entriesOut, double[] areasOut)
        {
            var    verts = mesh.Vertices;
            int    n     = verts.Count;
            double t     = 1.0 / 6.0;

            Array.Clear(entriesOut, 0, n * n);
            Array.Clear(areasOut, 0, n);

            // iterate faces to collect weights and vertex areas (upper triangular only)
            foreach (MeshFace mf in mesh.Faces)
            {
                // circulate verts in face
                for (int i = 0; i < 3; i++)
                {
                    int i0 = mf[i];
                    int i1 = mf[(i + 1) % 3];
                    int i2 = mf[(i + 2) % 3];

                    Vec3d v0 = verts[i0] - verts[i2];
                    Vec3d v1 = verts[i1] - verts[i2];

                    // add to vertex area
                    double a = Vec3d.CrossProduct(v0, v1).Length;
                    areasOut[i0] += a * t;

                    // add to edge cotangent weights (assumes consistent face orientation)
                    if (i1 < i0)
                    {
                        entriesOut[i0 * n + i1] += 0.5 * v0 * v1 / a;
                    }
                    else
                    {
                        entriesOut[i1 * n + i0] += 0.5 * v0 * v1 / a;
                    }
                }
            }

            // normalize weights with areas and sum along diagonals
            for (int i = 0; i < n; i++)
            {
                int ii = i * n + i;

                for (int j = i + 1; j < n; j++)
                {
                    double w = entriesOut[i * n + j];
                    w /= Math.Sqrt(areasOut[i] * areasOut[j]);

                    // set symmetric entries
                    entriesOut[i * n + j] = entriesOut[j * n + i] = w;

                    // sum along diagonal entries
                    entriesOut[j * n + j] -= w;
                    entriesOut[ii]        -= w;
                }
            }
        }