void SurfacePins::add_elastic_gradient_block_diagonal(RawArray<SymmetricMatrix<T,m>> dFdX) const { GEODE_ASSERT(dFdX.size()==mass.size()); for (int i=0;i<particles.size();i++) { int p = particles[i]; dFdX[p] -= scaled_outer_product(k[i],info[i].normal); // Ignores a curvature term if the closest point is on an edge or vertex } }
template<class TV> static Matrix<T,TV::m+1> affine_register_helper(RawArray<const TV> X0, RawArray<const TV> X1, RawArray<const T> mass) { typedef typename TV::Scalar T; static const int d = TV::m; const int n = X0.size(); GEODE_ASSERT(n==X1.size() && (mass.size()==0 || mass.size()==n)); const bool weighted = mass.size() == n; const T total = weighted ? mass.sum() : n; if (!total) return Matrix<T,d+1>::identity_matrix(); // Compute centers of mass TV c0, c1; if (weighted) { for (int i=0;i<n;i++) { c0 += mass[i]*X0[i]; c1 += mass[i]*X1[i]; } } else { c0 = X0.sum(); c1 = X1.sum(); } c0 /= total; c1 /= total; // Compute covariances SymmetricMatrix<T,d> cov00 = scaled_outer_product(-total,c0); Matrix<T,d> cov01 = outer_product(-total*c1,c0); if (weighted) for(int i=0;i<n;i++) { cov00 += scaled_outer_product(mass[i],X0[i]); cov01 += outer_product(mass[i]*X1[i],X0[i]); } else for (int i=0;i<n;i++) { cov00 += outer_product(X0[i]); cov01 += outer_product(X1[i],X0[i]); } // Compute transform const Matrix<T,d> A = cov01*cov00.inverse(); const TV t = c1-A*c0; auto tA = Matrix<T,d+1>::from_linear(A); tA.set_translation(t); return tA; }