// Result must be as large as Mesh.MaxVertexID public bool Solve(Vector3d[] Result) { if (WeightsM == null) { Initialize(); // force initialize... } UpdateForSolve(); // use initial positions as initial solution. Array.Copy(Px, Sx, N); Array.Copy(Py, Sy, N); Array.Copy(Pz, Sz, N); Action <double[], double[]> CombinedMultiply = (X, B) => { // packed multiply is 3-4x faster... //M.Multiply(X, B); PackedM.Multiply(X, B); for (int i = 0; i < N; ++i) { B[i] += WeightsM.D[i] * X[i]; } }; SparseSymmetricCG SolverX = new SparseSymmetricCG() { B = Bx, X = Sx, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverY = new SparseSymmetricCG() { B = By, X = Sy, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverZ = new SparseSymmetricCG() { B = Bz, X = Sz, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG[] solvers = new SparseSymmetricCG[3] { SolverX, SolverY, SolverZ }; bool[] ok = new bool[3]; int[] indices = new int[3] { 0, 1, 2 }; // preconditioned solve is slower =\ //Action<int> SolveF = (i) => { ok[i] = solvers[i].SolvePreconditioned(); }; Action <int> SolveF = (i) => { ok[i] = solvers[i].Solve(); }; gParallel.ForEach(indices, SolveF); if (ok[0] == false || ok[1] == false || ok[2] == false) { return(false); } for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Result[vid] = new Vector3d(Sx[i], Sy[i], Sz[i]); } // apply post-fixed constraints if (HavePostFixedConstraints) { foreach (var constraint in SoftConstraints) { if (constraint.Value.PostFix) { int vid = constraint.Key; Result[vid] = constraint.Value.Position; } } } return(true); }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3d v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; // TODO: Investigate: is this ia bug? // Source https://github.com/ZelimDamian/geometry3Sharp/commit/7a50d8de10faad762e726e60956acc4bdc5456b5 // makes the following line M.Set(i, i, sum_w); M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); // only works if M is symmetric!! PackedM = M.SquarePackedParallel(); } else { PackedM = new PackedSparseMatrix(M); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; PackedM.Multiply(Px, MLx); PackedM.Multiply(Py, MLy); PackedM.Multiply(Pz, MLz); // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; need_solve_update = true; UpdateForSolve(); }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3d v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); // only works if M is symmetric!! PackedM = M.SquarePackedParallel(); } else { PackedM = new PackedSparseMatrix(M); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; PackedM.Multiply(Px, MLx); PackedM.Multiply(Py, MLy); PackedM.Multiply(Pz, MLz); // zero out...this is the smoothing bit! for (int i = 0; i < Px.Length; ++i) { MLx[i] = 0; MLy[i] = 0; MLz[i] = 0; } // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; need_solve_update = true; UpdateForSolve(); }
public void Initialize() { int NV = Curve.VertexCount; ToCurveV = new int[NV]; ToIndex = new int[NV]; N = 0; for (int k = 0; k < NV; k++) { int vid = k; ToCurveV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToCurveV[i]; Vector3d v = Curve.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = (i == 0 || i == N - 1) ? 1 : 2; } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToCurveV[i]; int n = nbr_counts[i]; Index2i nbrs = Curve.Neighbours(vid); double sum_w = 0; for (int k = 0; k < 2; ++k) { int nbrvid = nbrs[k]; if (nbrvid == -1) { continue; } int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options double w = -1; //double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); // only works if M is symmetric!! PackedM = M.SquarePackedParallel(); } else { PackedM = new PackedSparseMatrix(M); } // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; PackedM.Multiply(Px, MLx); PackedM.Multiply(Py, MLy); PackedM.Multiply(Pz, MLz); // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; need_solve_update = true; UpdateForSolve(); }