private void ApplyHarmonicSolver_Cholmod() { // --- build up lefthand side matrix A int vn = mesh.VertexCount; int fn = mesh.FaceCount; int bn = this.sourceVertices.Count + this.sinkVertices.Count; int m = vn+bn; if (this.sparseSolver != null) this.sparseSolver.Release(); this.sparseSolver = new CholmodSolver(); this.sparseSolver.InitializeMatrixA(m, vn); for (int i = 0, j = 0; i < fn; i++, j += 3) { int c1 = mesh.FaceIndex[j]; int c2 = mesh.FaceIndex[j + 1]; int c3 = mesh.FaceIndex[j + 2]; Vector3d v1 = new Vector3d(mesh.VertexPos, c1 * 3); Vector3d v2 = new Vector3d(mesh.VertexPos, c2 * 3); Vector3d v3 = new Vector3d(mesh.VertexPos, c3 * 3); double cot1 = (v2 - v1).Dot(v3 - v1) / (v2 - v1).Cross(v3 - v1).Length(); double cot2 = (v3 - v2).Dot(v1 - v2) / (v3 - v2).Cross(v1 - v2).Length(); double cot3 = (v1 - v3).Dot(v2 - v3) / (v1 - v3).Cross(v2 - v3).Length(); sparseSolver.Add_Coef(c2, c2, -cot1); sparseSolver.Add_Coef(c2, c3, cot1); sparseSolver.Add_Coef(c3, c3, -cot1); sparseSolver.Add_Coef(c3, c2, cot1); sparseSolver.Add_Coef(c3, c3, -cot2); sparseSolver.Add_Coef(c3, c1, cot2); sparseSolver.Add_Coef(c1, c1, -cot2); sparseSolver.Add_Coef(c1, c3, cot2); sparseSolver.Add_Coef(c1, c1, -cot3); sparseSolver.Add_Coef(c1, c2, cot3); sparseSolver.Add_Coef(c2, c2, -cot3); sparseSolver.Add_Coef(c2, c1, cot3); } // add positional weights int index = 0; foreach (int v in sourceVertices) { sparseSolver.Add_Coef(vn + index, v, 1.0 * ConstantWeight); ++index; } foreach (int v in sinkVertices) { sparseSolver.Add_Coef(vn + index, v, 1.0 * ConstantWeight); ++index; } if (!opt.UseAtb) m = vn; double[] b = new double[m]; double[] x = new double[vn]; // -- assign values to the right hand side b,-- Ax=b if (opt.UseAtb) { for (int j = 0; j < b.Length; j++) b[j] = 0; int count = 0; for (int j = 0; j < sourceVertices.Count; ++j, ++count) b[vn + j] = 1.0 * ConstantWeight; for (int j = 0; j < sinkVertices.Count; ++j) b[vn + count + j] = 0.0; } else // set by user.. { foreach (int v in this.sourceVertices) b[v] = 1.0 * ConstantWeight * ConstantWeight; } fixed (double* _b = b) { sparseSolver.InitializeMatrixB(_b, m, 1); } sparseSolver.InitializeSolver(); sparseSolver.SetFinalPack(0); sparseSolver.Factorize(); fixed (double* _x = x) { sparseSolver.Linear_Solve(_x, !opt.UseAtb); } this.harmonicField = x; }
// main function private void ComputeBezierControlPoints() { CholmodSolver cholmodSolver = new CholmodSolver(); int n = numOfPoints - 2; cholmodSolver.InitializeMatrixA(n, n); for (int i = 0; i < n; ++i) { if (i == 0) { cholmodSolver.Add_Coef(i, i, 4); cholmodSolver.Add_Coef(i, i + 1, 1); } else if (i == n - 1) { cholmodSolver.Add_Coef(i, i, 4); cholmodSolver.Add_Coef(i, i - 1, 1); } else { cholmodSolver.Add_Coef(i, i - 1, 1); cholmodSolver.Add_Coef(i, i, 4); cholmodSolver.Add_Coef(i, i + 1, 1); } } // factorize cholmodSolver.InitializeSolver(); cholmodSolver.SetFinalPack(0); cholmodSolver.Factorize(); // rhs double[] b = new double[n]; double[] x = new double[n]; for (int k = 0; k < dimension; ++k) { for (int i = 0; i < n; ++i) { double r = 6.0; Vector2d pt; if (i == 0) { pt = r * inputPoints[1] - inputPoints[0]; } else if (i == n - 1) { pt = r * inputPoints[i + 1] - inputPoints[i + 2]; } else { pt = r * inputPoints[i + 1]; } switch (k) { case 0: b[i] = pt.x; // (inputPoints[t].x - inputPoints[s].x); break; case 1: b[i] = pt.y; //(inputPoints[t].y - inputPoints[s].y); break; } } // solve fixed(double *_b = b) { cholmodSolver.InitializeMatrixB(_b, n, 1); } fixed(double *_x = x) { cholmodSolver.Linear_Solve(_x, false); } // assign for (int i = 0; i < n; ++i) { int tt = i + 1; switch (k) { case 0: this.B[tt].x = x[i]; break; case 1: this.B[tt].y = x[i]; break; } } } B[0] = inputPoints[0]; B[B.Length - 1] = inputPoints[inputPoints.Length - 1]; cholmodSolver.Release(); }