IGL_INLINE void igl::PolyVectorFieldFinder<DerivedV, DerivedF>::setFieldFromGeneralCoefficients(const std::vector<Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1>> &coeffs, std::vector<Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2>> &pv) { pv.assign(n, Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2>::Zero(numF, 2)); for (int i = 0; i <numF; ++i) { // poly coefficients: 1, 0, -Acoeff, 0, Bcoeff // matlab code from roots (given there are no trailing zeros in the polynomial coefficients) Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1> polyCoeff; polyCoeff.setZero(2*n+1,1); polyCoeff[0] = 1.; int sign = 1; for (int k =0; k<n; ++k) { sign = -sign; int degree = 2*(k+1); polyCoeff[degree] = (1.*sign)*coeffs[k](i); } Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1> roots; igl::polyRoots<std::complex<typename DerivedV::Scalar>, typename DerivedV::Scalar >(polyCoeff,roots); Eigen::VectorXi done; done.setZero(2*n,1); Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1> u(n,1); int ind =0; for (int k=0; k<2*n; ++k) { if (done[k]) continue; u[ind] = roots[k]; done[k] = 1; int mini = -1; double mind = 1e10; for (int l =k+1; l<2*n; ++l) { double dist = abs(roots[l]+u[ind]); if (dist<mind) { mind = dist; mini = l; } } done[mini] = 1; ind ++; } for (int k=0; k<n; ++k) { pv[k](i,0) = real(u[k]); pv[k](i,1) = imag(u[k]); } } }
IGL_INLINE void igl::PolyVectorFieldFinder<DerivedV, DerivedF>:: minQuadWithKnownMini(const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &Q, const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &f, const Eigen::VectorXi isConstrained, const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &xknown, Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &x) { int N = Q.rows(); int nc = xknown.rows(); Eigen::VectorXi known; known.setZero(nc,1); Eigen::VectorXi unknown; unknown.setZero(N-nc,1); int indk = 0, indu = 0; for (int i = 0; i<N; ++i) if (isConstrained[i]) { known[indk] = i; indk++; } else { unknown[indu] = i; indu++; } Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> Quu, Quk; igl::slice(Q,unknown, unknown, Quu); igl::slice(Q,unknown, known, Quk); std::vector<typename Eigen::Triplet<std::complex<typename DerivedV::Scalar> > > tripletList; Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > fu(N-nc,1); igl::slice(f,unknown, Eigen::VectorXi::Zero(1,1), fu); Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > rhs = (Quk*xknown).sparseView()+.5*fu; Eigen::SparseLU< Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>>> solver; solver.compute(-Quu); if(solver.info()!=Eigen::Success) { std::cerr<<"Decomposition failed!"<<std::endl; return; } Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> b = solver.solve(rhs); if(solver.info()!=Eigen::Success) { std::cerr<<"Solving failed!"<<std::endl; return; } indk = 0, indu = 0; x.setZero(N,1); for (int i = 0; i<N; ++i) if (isConstrained[i]) x[i] = xknown[indk++]; else x[i] = b.coeff(indu++,0); }
void pcl::Permutohedral::init (const std::vector<float> &feature, const int feature_dimension, const int N) { N_ = N; d_ = feature_dimension; // Create hash table std::vector<std::vector<short> > keys; keys.reserve ((d_+1) * N_); std::multimap<size_t, int> hash_table; // reserve class memory if (offset_.size () > 0) offset_.clear (); offset_.resize ((d_ + 1) * N_); if (barycentric_.size () > 0) barycentric_.clear (); barycentric_.resize ((d_ + 1) * N_); // create vectors and matrices Eigen::VectorXf scale_factor = Eigen::VectorXf::Zero (d_); Eigen::VectorXf elevated = Eigen::VectorXf::Zero (d_ + 1); Eigen::VectorXf rem0 = Eigen::VectorXf::Zero (d_+1); Eigen::VectorXf barycentric = Eigen::VectorXf::Zero (d_+2); Eigen::VectorXi rank = Eigen::VectorXi::Zero (d_+1); Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> canonical; canonical = Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>::Zero (d_+1, d_+1); //short * key = new short[d_+1]; std::vector<short> key (d_+1); // Compute the canonical simple for (int i = 0; i <= d_; i++) { for (int j = 0; j <= (d_ - i); j++) canonical (j, i) = i; for (int j = (d_ - i + 1); j <= d_; j++) canonical (j, i) = i - (d_ + 1); } // Expected standard deviation of our filter (p.6 in [Adams etal 2010]) float inv_std_dev = std::sqrt (2.0f / 3.0f) * static_cast<float> (d_ + 1); // Compute the diagonal part of E (p.5 in [Adams etal 2010]) for (int i = 0; i < d_; i++) scale_factor (i) = 1.0f / std::sqrt (static_cast<float> (i + 2) * static_cast<float> (i + 1)) * inv_std_dev; // Compute the simplex each feature lies in for (int k = 0; k < N_; k++) //for (int k = 0; k < 5; k++) { // Elevate the feature (y = Ep, see p.5 in [Adams etal 2010]) int index = k * feature_dimension; // sm contains the sum of 1..n of our faeture vector float sm = 0; for (int j = d_; j > 0; j--) { float cf = feature[index + j-1] * scale_factor (j-1); elevated (j) = sm - static_cast<float> (j) * cf; sm += cf; } elevated (0) = sm; // Find the closest 0-colored simplex through rounding float down_factor = 1.0f / static_cast<float>(d_+1); float up_factor = static_cast<float>(d_+1); int sum = 0; for (int j = 0; j <= d_; j++){ float rd = floorf (0.5f + (down_factor * elevated (j))) ; rem0 (j) = rd * up_factor; sum += static_cast<int> (rd); } // rank differential to find the permutation between this simplex and the canonical one. // (See pg. 3-4 in paper.) rank.setZero (); Eigen::VectorXf tmp = elevated - rem0; for (int i = 0; i < d_; i++){ for (int j = i+1; j <= d_; j++) if (tmp (i) < tmp (j)) rank (i)++; else rank (j)++; } // If the point doesn't lie on the plane (sum != 0) bring it back for (int j = 0; j <= d_; j++){ rank (j) += sum; if (rank (j) < 0){ rank (j) += d_+1; rem0 (j) += static_cast<float> (d_ + 1); } else if (rank (j) > d_){ rank (j) -= d_+1; rem0 (j) -= static_cast<float> (d_ + 1); } } // Compute the barycentric coordinates (p.10 in [Adams etal 2010]) barycentric.setZero (); Eigen::VectorXf v = (elevated - rem0) * down_factor; for (int j = 0; j <= d_; j++){ barycentric (d_ - rank (j) ) += v (j); barycentric (d_ + 1 - rank (j)) -= v (j); } // Wrap around barycentric (0) += 1.0f + barycentric (d_+1); // Compute all vertices and their offset for (int remainder = 0; remainder <= d_; remainder++) { for (int j = 0; j < d_; j++) key[j] = static_cast<short> (rem0 (j) + static_cast<float> (canonical ( rank (j), remainder))); // insert key in hash table size_t hash_key = generateHashKey (key); auto it = hash_table.find (hash_key); int key_index = -1; if (it != hash_table.end ()) { key_index = it->second; // check if key is the right one int tmp_key_index = -1; //for (int ii = key_index; ii < keys.size (); ii++) for (; it != hash_table.end (); ++it) { int ii = it->second; bool same = true; std::vector<short> k = keys[ii]; for (size_t i_k = 0; i_k < k.size (); i_k++) { if (key[i_k] != k[i_k]) { same = false; break; } } if (same) { tmp_key_index = ii; break; } } if (tmp_key_index == -1) { key_index = static_cast<int> (keys.size ()); keys.push_back (key); hash_table.insert (std::pair<size_t, int> (hash_key, key_index)); } else key_index = tmp_key_index; } else { key_index = static_cast<int> (keys.size ()); keys.push_back (key); hash_table.insert (std::pair<size_t, int> (hash_key, key_index)); } offset_[ k * (d_ + 1) + remainder ] = static_cast<float> (key_index); barycentric_[ k * (d_ + 1) + remainder ] = barycentric (remainder); } } // Find the Neighbors of each lattice point // Get the number of vertices in the lattice M_ = static_cast<int> (hash_table.size()); // Create the neighborhood structure if (blur_neighbors_.size () > 0) blur_neighbors_.clear (); blur_neighbors_.resize ((d_+1)*M_); std::vector<short> n1 (d_+1); std::vector<short> n2 (d_+1); // For each of d+1 axes, for (int j = 0; j <= d_; j++) { for (int i = 0; i < M_; i++) { std::vector<short> key = keys[i]; for (int k=0; k<d_; k++){ n1[k] = static_cast<short> (key[k] - 1); n2[k] = static_cast<short> (key[k] + 1); } n1[j] = static_cast<short> (key[j] + d_); n2[j] = static_cast<short> (key[j] - d_); std::multimap<size_t ,int>::iterator it; size_t hash_key; int key_index = -1; hash_key = generateHashKey (n1); it = hash_table.find (hash_key); if (it != hash_table.end ()) key_index = it->second; blur_neighbors_[j*M_+i].n1 = key_index; key_index = -1; hash_key = generateHashKey (n2); it = hash_table.find (hash_key); if (it != hash_table.end ()) key_index = it->second; blur_neighbors_[j*M_+i].n2 = key_index; } } }
IGL_INLINE void igl::parallel_transport_angles( const Eigen::PlainObjectBase<DerivedV>& V, const Eigen::PlainObjectBase<DerivedF>& F, const Eigen::PlainObjectBase<DerivedV>& FN, const Eigen::MatrixXi &E2F, const Eigen::MatrixXi &F2E, Eigen::PlainObjectBase<DerivedK> &K) { int numE = E2F.rows(); Eigen::VectorXi isBorderEdge; isBorderEdge.setZero(numE,1); for(unsigned i=0; i<numE; ++i) { if ((E2F(i,0) == -1) || ((E2F(i,1) == -1))) isBorderEdge[i] = 1; } K.setZero(numE); // For every non-border edge for (unsigned eid=0; eid<numE; ++eid) { if (!isBorderEdge[eid]) { int fid0 = E2F(eid,0); int fid1 = E2F(eid,1); Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0); // Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1); // find common edge on triangle 0 and 1 int fid0_vc = -1; int fid1_vc = -1; for (unsigned i=0;i<3;++i) { if (F2E(fid0,i) == eid) fid0_vc = i; if (F2E(fid1,i) == eid) fid1_vc = i; } assert(fid0_vc != -1); assert(fid1_vc != -1); Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc)); common_edge.normalize(); // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P; Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc)); Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge); P << common_edge, tmp, N0; // P.transposeInPlace(); Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0; V0.row(0) = V.row(F(fid0,0)) -o; V0.row(1) = V.row(F(fid0,1)) -o; V0.row(2) = V.row(F(fid0,2)) -o; V0 = (P*V0.transpose()).transpose(); // assert(V0(0,2) < 1e-10); // assert(V0(1,2) < 1e-10); // assert(V0(2,2) < 1e-10); Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1; V1.row(0) = V.row(F(fid1,0)) -o; V1.row(1) = V.row(F(fid1,1)) -o; V1.row(2) = V.row(F(fid1,2)) -o; V1 = (P*V1.transpose()).transpose(); // assert(V1(fid1_vc,2) < 10e-10); // assert(V1((fid1_vc+1)%3,2) < 10e-10); // compute rotation R such that R * N1 = N0 // i.e. map both triangles to the same plane double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1)); Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R; R << 1, 0, 0, 0, cos(alpha), -sin(alpha) , 0, sin(alpha), cos(alpha); V1 = (R*V1.transpose()).transpose(); // assert(V1(0,2) < 1e-10); // assert(V1(1,2) < 1e-10); // assert(V1(2,2) < 1e-10); // measure the angle between the reference frames // k_ij is the angle between the triangle on the left and the one on the right Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0); Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0); ref0.normalize(); ref1.normalize(); double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0)); // just to be sure, rotate ref0 using angle ktemp... Eigen::Matrix<typename DerivedV::Scalar,2,2> R2; R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp); // Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose(); // assert(tmp1(0) - ref1(0) < 1e-10); // assert(tmp1(1) - ref1(1) < 1e-10); K[eid] = ktemp; } } }
// A tet is organized in the following fashion: // // 0 // // 3 (3 is in the background; 1 and 2 are in the foreground) // 2 1 // // So the faces (with counterclockwise normals) are: // (0 1 3) // (0 2 1) // (3 2 0) // (1 2 3) // // // This method will perform three steps: // 1. Add all faces, duplicating ones on the interior // 2. Remove all duplicate verts (might have been caused during #1) // 3. Remove all duplicate faces void marching_tets( const Eigen::MatrixXd& V, const Eigen::MatrixXi& T, const Eigen::VectorXd& H, double offset, Eigen::MatrixXd& NV, Eigen::MatrixXi& NF, Eigen::VectorXi& I) { min_how_much = 1; max_how_much = 0; using namespace Eigen; using namespace std; // Count the faces. std::map<std::vector<int>, int> face_counts; for (int i = 0; i < T.rows(); ++i) { std::vector<std::vector<int> > fs; fs.push_back({T(i, 0), T(i, 1), T(i, 3)}); fs.push_back({T(i, 0), T(i, 2), T(i, 1)}); fs.push_back({T(i, 3), T(i, 2), T(i, 0)}); fs.push_back({T(i, 1), T(i, 2), T(i, 3)}); for (auto &f : fs) { std::sort(f.begin(), f.end()); // Add it to the map. face_counts[f]++; } } vector<Eigen::RowVector3i> faces; vector<int> faces_markers; vector<Eigen::RowVector3d> new_verts; int times[6]; for (int i = 0; i < 6; i++) { times[i] = 0; } // Create data structure. MarchingTetsDat dd(V, H, faces, faces_markers, face_counts, new_verts, offset); int numEq = 0; // Check each tet face, add as needed. for (int i = 0; i < T.rows(); ++i) { // See if the tet is entirely inside. vector<int> inside, outside, inside_t, outside_t, identical; for (int j = 0; j < T.cols(); ++j) { //if (H(T(i, j)) > offset + 1e-4) { if (H(T(i, j)) > offset) { outside.push_back(j); } else if (H(T(i, j)) < offset) { inside.push_back(j); } else { numEq++; identical.push_back(j); } if (H(T(i, j)) == GLOBAL::outside_temp) { outside_t.push_back(j); } else if (H(T(i, j)) == GLOBAL::inside_temp) { inside_t.push_back(j); } } // Ignore this tet if it's entirely outside. if (outside.size() == 4) { continue; } if (outside.size() == 0 && inside.size() == 0) { // degenerate, ignore. printf("WARNING: degenerate tet face found!!\n"); } else if (inside.size() == 0 && identical.size() < 3) { // Nothing to add. } else if (identical.size() == 3) { //addOrig(T.row(i), 7, dd.faces, dd.faces_markers); // Ignore it if there's only one on the outside. //if (inside.size() == 0) continue; if (outside.size() == 0) continue; times[1]++; // Add just a single face (always) int i1 = T(i,identical[0]), i2 = T(i,identical[1]), i3 = T(i,identical[2]); Eigen::RowVector3i f({i1, i2, i3}); dd.faces.push_back(f); dd.faces_markers.push_back(1); } else if (outside.size() == 0) { // (these are colored blue) times[0]++; // (A) Takes care of: // inside: 1, identical: 3 (remove three duplicated faces later) // inside: 2, identical: 2 (remove all four duplicated faces later) // inside: 3, identical: 1 (remove all four duplicated faces later) // inside: 4, identical: 0 (remove all four duplicated faces later) case0Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t); } else if (inside.size() == 1) { // (these are colored green) times[2]++; // (B) Takes care of: // inside: 1 outside: 3 // inside: 1 outside: 2 identical: 1 // inside: 1 outside: 1 identical: 2 // case1In(dd, T.row(i), inside, outside, identical, inside_t, outside_t); } else if (inside.size() == 3 && outside.size() == 1) { // (these are colored orange) times[3]++; // (C) takes care of: // inside: 3 outside: 1 // case3In1Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t); } else if (inside.size() == 2 && outside.size() >= 1) { // (these are colored red) times[4]++; // (D) takes care of: // inside: 2 outside: 1 identical: 1 // inside: 2 outside: 2 identical: 0 // case2In2Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t); } else { times[5]++; fprintf(stderr, "WARN: marching tets found something weird, with in:%lu out:%lu\n", inside.size(), outside.size()); } } printf("Finished marching tets with usages:\n"); for (int i = 0; i < 6; ++i) { printf(" %d: %d\n", i, times[i]); } printf("how_much is %lf and EPS is %lf\n", min_how_much, GLOBAL::EPS); printf(" max is %lf\n", max_how_much); printf("Num equal is %d\n", numEq); // Copy verts NV.resize(V.rows() + new_verts.size(), 3); for (int i = 0; i < V.rows(); ++i) { NV.row(i) = V.row(i); } for (int i = 0; i < new_verts.size(); ++i) { NV.row(i + V.rows()) = new_verts[i]; } // Set I I.resize(NV.rows()); for (int i = 0; i < I.rows(); ++i) { if (i < V.rows()) { I(i) = i; } else { I(i) = -1; } } Eigen::VectorXi facesMarkers; facesMarkers.resize(faces.size()); // Copy faces NF.resize(faces.size(), 3); for (int i = 0; i < faces.size(); ++i) { NF.row(i) = faces[i]; facesMarkers(i) = faces_markers[i]; } Eigen::MatrixXd newV; Eigen::MatrixXi newF; Eigen::VectorXi SVJ, SVI, I2; // Helpers::viewTriMesh(NV, NF, facesMarkers); //igl::writeOFF("offset_mesh.off", NV, NF) Helpers::writeMeshWithMarkers("offset_mesh", NV, NF, facesMarkers); /* igl::collapse_small_triangles(NV, NF, 1e-8, newF); printf("Collapsed %d small triangles\n", NF.rows() - newF.rows()); NF = newF; */ ///* igl::remove_duplicate_vertices(NV, NF, 1e-20, newV, SVI, SVJ, newF); I2.resize(newV.rows()); I2.setConstant(-1); for (int i = 0; i < NV.rows(); ++i) { if (I2(SVJ(i)) == -1) { I2(SVJ(i)) = I(i); } else { I2(SVJ(i)) = std::min(I2(SVJ(i)), I(i)); } } NF = newF; NV = newV; I = I2; // Now see if we have duplicated faces. //igl::resolve_duplicated_faces(NF, newF, SVJ); //NF = newF; //*/ // Other option is to do these two: // These are bad because sometimes the "small" triangles are not area zero, // and doing the removeDuplicates will delete these triangles and make the // mesh non-manifold. Better to wait for remeshing later. //Helpers::removeDuplicates(NV, NF, I); //Helpers::collapseSmallTriangles(NV, NF); igl::remove_unreferenced(NV, NF, newV, newF, SVI, SVJ); I2.resize(newV.rows()); I2.setConstant(-1); for (int i = 0; i < I2.rows(); ++i) { I2(i) = I(SVJ(i)); } I = I2; NV = newV; NF = newF; // orient everything correctly. Eigen::VectorXi C; igl::orientable_patches(NF, C); igl::bfs_orient(NF, newF, C); NF = newF; igl::orient_outward(NV, NF, C, newF, SVJ); NF = newF; //igl::writeOFF("offset_mesh_normals.off", NV, NF); #ifdef DEBUG_MESH if (!Helpers::isMeshOkay(NV, NF)) { printf("Error: Mesh is not okay at first...\n"); } if (!Helpers::isManifold(NV, NF, I)) { printf("Error: Mesh from marching tets not manifold!\n"); Eigen::VectorXi temp; temp.resize(I.rows()); temp.setZero(); Helpers::isManifold(NV, NF, temp, true); Helpers::viewTriMesh(NV, NF, temp); Helpers::writeMeshWithMarkers("marching_tets_manifold", NV, NF, temp); cout << "See marching_tets_manifold.off for problems.\n"; exit(1); } #endif }