/// <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; } } }