// Diffuse the curvatures across the mesh void diffuse_curv(TriMesh *themesh, float sigma) { themesh->need_normals(); themesh->need_pointareas(); themesh->need_curvatures(); themesh->need_neighbors(); int nv = themesh->vertices.size(); dprintf("\rSmoothing curvatures... "); timestamp t = now(); float invsigma2 = 1.0f / sqr(sigma); vector<vec> cflt(nv); #pragma omp parallel { // Thread-local flags vector<unsigned> flags(nv); unsigned flag_curr = 0; #pragma omp for for (int i = 0; i < nv; i++) diffuse_vert_field(themesh, flags, flag_curr, AccumCurv(), i, invsigma2, cflt[i]); #pragma omp for for (int i = 0; i < nv; i++) diagonalize_curv(themesh->pdir1[i], themesh->pdir2[i], cflt[i][0], cflt[i][1], cflt[i][2], themesh->normals[i], themesh->pdir1[i], themesh->pdir2[i], themesh->curv1[i], themesh->curv2[i]); } // #pragma omp parallel dprintf("Done. Filtering took %f sec.\n", now() - t); }
void Curvature::computePrincipalCurvatures( Surface_mesh * src_mesh ) { computePointAreas(src_mesh); uint nv = src_mesh->n_vertices(), nf = src_mesh->n_faces(); curv1.resize(nv); curv2.resize(nv); pdir1.resize(nv); pdir2.resize(nv); std::vector<double> curv12(nv); Surface_mesh::Vertex_property<Point> points = src_mesh->vertex_property<Point>("v:point"); Surface_mesh::Vertex_property<Normal> normals = src_mesh->vertex_property<Normal>("v:normal"); Surface_mesh::Face_iterator fit, fend = src_mesh->faces_end(); Surface_mesh::Vertex_around_face_circulator fvit, fvend; Surface_mesh::Vertex_iterator vit, vend = src_mesh->vertices_end(); //#pragma omp parallel for for (fit = src_mesh->faces_begin(); fit != fend; ++fit) { fvit = src_mesh->vertices(fit); uint vi0 = ((Vertex)fvit).idx(); Point v0 = points[fvit]; ++fvit; uint vi1 = ((Vertex)fvit).idx(); Point v1 = points[fvit]; ++fvit; uint vi2 = ((Vertex)fvit).idx(); Point v2 = points[fvit]; pdir1[vi0] = v1 - v0; pdir1[vi1] = v2 - v1; pdir1[vi2] = v0 - v2; } //#pragma omp parallel for for (vit = src_mesh->vertices_begin(); vit != vend; ++vit) { uint vi = ((Vertex)vit).idx(); pdir1[vi] = cross(pdir1[vi], normals[vit]); pdir1[vi].normalize(); pdir2[vi] = cross(normals[vit], pdir1[vi]); } // Compute curvature per-face //#pragma omp parallel for for (fit = src_mesh->faces_begin(); fit != fend; ++fit) { uint i = ((Surface_mesh::Face)fit).idx(); // face index uint vi[3]; Normal vn[3]; fvit = src_mesh->vertices(fit); vi[0] = ((Vertex)fvit).idx(); Point v0 = points[fvit]; vn[0] = normals[fvit]; ++fvit; vi[1] = ((Vertex)fvit).idx(); Point v1 = points[fvit]; vn[1] = normals[fvit]; ++fvit; vi[2] = ((Vertex)fvit).idx(); Point v2 = points[fvit]; vn[2] = normals[fvit]; ++fvit; // Edges Point e[3] = {v2 - v1, v0 - v2, v1 - v0}; // N-T-B coordinate system per face Point t = e[0]; t.normalize(); Point n = cross(e[0], e[1]); Point b = cross(n, t); b.normalize(); // Estimate curvature based on variation of normals // along edges double m[3] = { 0, 0, 0 }; double w[3][3] = { {0,0,0}, {0,0,0}, {0,0,0} }; for (int j = 0; j < 3; j++) { double u = dot(e[j], t); double v = dot(e[j], b); w[0][0] += u*u; w[0][1] += u*v; //w[1][1] += v*v + u*u; //w[1][2] += u*v; w[2][2] += v*v; Point dn = vn[PREV_Index(j)] - vn[NEXT_Index(j)]; double dnu = dot(dn, t); double dnv = dot(dn, b); m[0] += dnu*u; m[1] += dnu*v + dnv*u; m[2] += dnv*v; } w[1][1] = w[0][0] + w[2][2]; w[1][2] = w[0][1]; // Least squares solution double diag[3]; if (!ldltdc<double,3>(w, diag)) { //printf("ldltdc failed!\n"); continue; } ldltsl<double,3>(w, diag, m, m); // Push it back out to the vertices for (uint j = 0; j < 3; j++) { int vj = vi[j]; double c1, c12, c2; proj_curv(t, b, m[0], m[1], m[2], pdir1[vj], pdir2[vj], c1, c12, c2); double wt = cornerareas[i][j] / pointareas[vj]; //#pragma omp atomic curv1[vj] += wt * c1; //#pragma omp atomic curv12[vj] += wt * c12; //#pragma omp atomic curv2[vj] += wt * c2; } } // Store results into Surface_mesh object Surface_mesh::Vertex_property<double> my_curv1 = src_mesh->vertex_property<double>("v:curv1"); Surface_mesh::Vertex_property<double> my_curv2 = src_mesh->vertex_property<double>("v:vurv2"); Surface_mesh::Vertex_property<Vec3d> my_pdir1 = src_mesh->vertex_property<Vec3d>("v:pdir1"); Surface_mesh::Vertex_property<Vec3d> my_pdir2 = src_mesh->vertex_property<Vec3d>("v:pdir2"); // Compute principal directions and curvatures at each vertex //#pragma omp parallel for for (vit = src_mesh->vertices_begin(); vit != vend; ++vit) { uint i = ((Surface_mesh::Vertex)vit).idx(); diagonalize_curv(pdir1[i], pdir2[i],curv1[i], curv12[i], curv2[i], normals[vit], pdir1[i], pdir2[i],curv1[i], curv2[i]); my_curv1[vit] = curv1[i]; my_curv2[vit] = curv2[i]; my_pdir1[vit] = pdir1[i]; my_pdir2[vit] = pdir2[i]; } }