#include "curvature.h" #include "util.h" #include void Courbures::normales_locales() { _mesh.request_vertex_normals(); size_t i; for (VertexHandle vh : _mesh.vertices()) { MyMesh::Normal normal(0,0,0); i = 0; for (MyMesh::FaceHandle vf : _mesh.vf_range(vh)) { i++; normal += _mesh.calc_face_normal(vf); } if (i != 0) { normal /= i; normal /= norm(normal); } _mesh.set_normal(vh, normal); } } void Courbures::get_two_neighborhood(std::vector &out, const MyMesh::VertexHandle vh) { auto flag_prop = OpenMesh::getOrMakeProperty(_mesh, "vprop_flag"); flag_prop.set_range(_mesh.vertices_begin(), _mesh.vertices_end(), false); // Parcours du 1-anneau flag_prop[vh] = true; for(VertexHandle vv : _mesh.vv_range(vh)) { out.push_back(vv); // ajout du point à la liste flag_prop[vv] = true; } if (out.size() >= 5) return; // Parcours du 1-anneau de chaque sommet du 1-anneau size_t old_size = out.size(); for (size_t i = 0; i < old_size; i++) { for (VertexHandle vv : _mesh.vv_range(out[i])) { if (!flag_prop[vv]) { out.push_back(vv); flag_prop[vv] = true; } } } } QuadPatch Courbures::fit_quad(MyMesh::VertexHandle vh) { static std::vector neigh; neigh.clear(); get_two_neighborhood(neigh, vh); if (neigh.size() < 5) throw "Quad fitting: not enough neighbors"; // Calcul de la matrice de changement de base Eigen::Vector3d Oz(0,0,1); Eigen::Vector3d axis = _mesh.normal(vh).cross(Oz); double sina = axis.norm(); double cosa = _mesh.normal(vh).dot(Oz); double angle; if (sina >= 0) { angle = acos(cosa); } else { angle = -acos(cosa); } axis = axis.normalized(); Eigen::AngleAxisd rot(angle, axis); Eigen::Translation3d trans(-_mesh.point(vh)); Eigen::Transform ch_base = rot * trans; // Calcul de la matrice / vecteur de moindres carrés linéaires (Eigen) Eigen::MatrixXd A(neigh.size(), 5); Eigen::VectorXd B(neigh.size()); for(size_t i = 0; i < neigh.size(); i++) { MyMesh::Point point = _mesh.point(neigh[i]); point = ch_base * point; // Application du changement de base B[i] = -point[2]; // -zi A(i, 0) = point[0] * point[0]; // xi^2 A(i, 1) = point[0] * point[1]; // xi*yi A(i, 2) = point[1] * point[1]; // yi^2 A(i, 3) = point[0]; // xi A(i, 4) = point[1]; // yi } // Résolution aux moindres carrés par SVD Eigen::VectorXd coef(5); coef = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(B); return QuadPatch(coef, ch_base); } void Courbures::compute_KH() { _mesh.add_property(vprop_K, "vprop_K"); _mesh.add_property(vprop_H, "vprop_H"); _mesh.add_property(vprop_quad, "vprop_quad"); for (VertexHandle vh : _mesh.vertices()) { QuadPatch q = fit_quad(vh); _mesh.property(vprop_quad, vh) = q; // K = det (K_P) = 4 a_0 a_2 - a_1 ^ 2 _mesh.property(vprop_K, vh) = 4 * q[0] * q[2] - q[1]*q[1]; // H = Tr (K_P) = a_0 + a_2 _mesh.property(vprop_H, vh) = q[0] + q[2]; } } void Courbures::set_fixed_colors() { size_t i = 0; for (VertexHandle vh : _mesh.vertices()) { if (i % 2) _mesh.set_color(vh, MyMesh::Color(0, 1, 0)); else _mesh.set_color(vh, MyMesh::Color(0, 0, 1)); i++; } } void Courbures::set_K_colors() { auto prop = _mesh.property(vprop_K); auto prop_data = prop.data_vector(); double avg = average(prop_data.begin(), prop_data.end()); double stddev = standard_deviation (prop_data.begin(), prop_data.end(), avg); std::cout << "K mean : " << avg << " - sigma : " << stddev << std::endl; for (VertexHandle vh : _mesh.vertices()) { double tmp = _mesh.property(vprop_K, vh) - avg; tmp = clamp(tmp, -stddev, +stddev); tmp = (tmp + stddev) / (2 * stddev); _mesh.set_color(vh, MyMesh::Color(tmp, .23, .5)); } }