void material::compute_kdtree() { assert(!tree_ && "only call this function once"); tree_ = create_kdtree(indices, get_vertices()); }
void LFS::compute(const std::vector<vec3>& vertices, double sliver_quality_degree /*= 0.01*/, const bool* feature_label /*= 0*/) { Delaunay* del = Delaunay::create("CGAL_spatial_sort") ; del->set_vertices(vertices) ; std::vector<int> tets ; del->get_tetras(tets, false) ; unsigned int nb_tets = (unsigned int)tets.size() / 4 ; //compute tets' circumcenter and radius std::vector<vec3> tet_circumcenter(nb_tets); std::vector<double> tet_radius(nb_tets); std::vector<bool> used_tet(nb_tets, false); // to avoid multiple insertion int nv = (int)vertices.size(); poles.clear(); poles.reserve(nv*2); std::vector<double> dis(nv, 0); std::vector<int> tetid(nv, -1); std::vector<bool> infinite_flag(nv, false); std::vector<bool> infinite_tet(nb_tets, false); N.clear(); N.resize(nv); std::fill(N.begin(),N.end(), vec3(0,0,0)); // N x + d = 0 is a plane equation std::vector<double> d(nv, 0); std::vector<bool> good_tetra(nb_tets, true); int start = 0; int vertex_id[4]; vec3 normal; double quality[6]; int bad_tetra = 0; const double mPI = 3.1415926535897932384626433832795; const double sliver_quality = sliver_quality_degree / 180. * mPI; for(unsigned int i = 0; i < nb_tets; i++) { //set id int inf_id = -1; for (int j = 0; j < 4; j++) { vertex_id[j] = tets[start+j]; if (vertex_id[j] == -1) { infinite_tet[i] = true; inf_id = j; } } if (!infinite_tet[i]) { bool suc = tetra_circumcenter_squaredradius( vertices[tets[start]], vertices[tets[start+1]], vertices[tets[start+2]], vertices[tets[start+3]], tet_circumcenter[i], tet_radius[i], quality); if ( suc == false || ( (quality[0] <= sliver_quality || quality[0] >= mPI - sliver_quality) && (quality[1] <= sliver_quality || quality[1] >= mPI - sliver_quality) && (quality[2] <= sliver_quality || quality[2] >= mPI - sliver_quality) && (quality[3] <= sliver_quality || quality[3] >= mPI - sliver_quality) && (quality[4] <= sliver_quality || quality[4] >= mPI - sliver_quality) && (quality[5] <= sliver_quality || quality[5] >= mPI - sliver_quality) ) ) { good_tetra[i] = false; bad_tetra++; } //set dis if (good_tetra[i]) { for (int j = 0; j < 4; j++) { if ( tet_radius[i] > dis[ vertex_id[j] ] ) { dis[ vertex_id[j] ] = tet_radius[i]; tetid[ vertex_id[j] ] = i; } } } } else { const int &id1 = vertex_id[(inf_id+1)%4]; const int &id2 = vertex_id[(inf_id+2)%4]; const int &id3 = vertex_id[(inf_id+3)%4]; infinite_flag[ id1 ] = true; infinite_flag[ id2 ] = true; infinite_flag[ id3 ] = true; normal = inf_id%2==0? normalize(cross(vertices[id3]-vertices[id1], vertices[id2]-vertices[id1])): normalize(cross(vertices[id2]-vertices[id1], vertices[id3]-vertices[id1])); N[id1] += normal; N[id2] += normal; N[id3] += normal; } start += 4; } std::cerr <<"Total tetrahedrons (including infinite tetras): " << nb_tets << std::endl; std::cerr <<"detected " << bad_tetra << " sliver tetrahedrons (min dihedral angle = " << sliver_quality_degree <<" degree" << std::endl; //set poles, first round for (int i = 0; i < nv; i++) { if (!infinite_flag[i]) { if ( used_tet[tetid[i]] == false && (feature_label == 0 || feature_label[i] == false)) { poles.push_back( tet_circumcenter[ tetid[i] ] ); used_tet[tetid[i]] = true; } N[i] = tet_circumcenter[ tetid[i] ] - vertices[i]; } d[i] = -Geex::dot(N[i], vertices[i]); } //set poles, second round std::fill(dis.begin(),dis.end(), 0); std::fill(tetid.begin(),tetid.end(), -1); start = 0; for (unsigned int i = 0; i < nb_tets; i++) { if (!infinite_tet[i] && good_tetra[i]) { for (int j = 0; j < 4; j++) { const int& vid = tets[start+j]; if ( tet_radius[i] > dis[ vid ] && Geex::dot(N[vid], tet_circumcenter[i])+ d[vid] < 0 ) { dis[vid] = tet_radius[i]; tetid[vid] = i; } } } start += 4; } for (int i = 0; i < nv; i++) { if ( tetid[i] >= 0 && used_tet[tetid[i]] == false && (feature_label == 0 || feature_label[i] == false)) { poles.push_back( tet_circumcenter[ tetid[i] ] ); used_tet[tetid[i]] = true; } } delete del ; create_kdtree(); }