// Return the number of connected components from the graph containing all edges and give, for each vertex, which component it belongs to (use BOOST GRAPH LIBRAIRY) int EdgeSetTopologyContainer::getNumberConnectedComponents(sofa::helper::vector<unsigned int>& components) { using namespace boost; typedef adjacency_list <vecS, vecS, undirectedS> Graph; Graph G; helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge; for (size_t k=0; k<m_edge.size(); ++k) { add_edge(m_edge[k][0], m_edge[k][1], G); } components.resize(num_vertices(G)); int num = (int) connected_components(G, &components[0]); return num; }
void Rendering::Mesh::init(FEMMesh* inputMesh) { if (inputMesh) { LOGI("Creating mapping between simulation mesh \"%s\" and surface mesh" ,inputMesh->filename.c_str()); static std::string input_filename; static sofa::helper::vector<Mat3x3d> bases; static sofa::helper::vector<Vec3d> centers; static Octree<Vec3d> octree; const TVecTetra& tetras = inputMesh->tetrahedra; const TVecCoord& in = inputMesh->positions; const TVecCoord& out = m_vertices; d_map_i.resize(out.size()); d_map_f.resize(out.size()); if (input_filename != inputMesh->filename || bases.size() != tetras.size()) // we have to recompute the octree and bases { input_filename = inputMesh->filename; sofa::helper::vector< BBox<Vec3d> > bbox; bases.resize(tetras.size()); centers.resize(tetras.size()); bbox.resize(tetras.size()); LOGI(" Preparing tetrahedra"); for (unsigned int t=0; t<tetras.size(); ++t) { Mat3x3d m, mt; m[0] = in[tetras[t][1]]-in[tetras[t][0]]; m[1] = in[tetras[t][2]]-in[tetras[t][0]]; m[2] = in[tetras[t][3]]-in[tetras[t][0]]; mt.transpose(m); bases[t].invert(mt); centers[t] = (in[tetras[t][0]]+in[tetras[t][1]]+in[tetras[t][2]]+in[tetras[t][3]])*0.25; bbox[t].add(tetras[t].begin(), tetras[t].end(), in); } LOGI(" Building octree"); octree.init(bbox,8,8); } LOGI( " Processing vertices" ); int outside = 0; sofa::helper::vector<Octree<Vec3d>*> cells; for (unsigned int i=0;i<out.size();i++) { Vec3d pos = out[i]; Vec3d coefs; int index = -1; double distance = 1e10; Octree<Vec3d>* cell = octree.findNear(pos); if (cell) { const sofa::helper::vector<int>& elems = cell->elems(); for (unsigned int e = 0; e < elems.size(); e++) { unsigned int t = elems[e]; Vec3d v = bases[t] * (pos - in[tetras[t][0]]); double d = std::max(std::max(-v[0],-v[1]),std::max(-v[2],v[0]+v[1]+v[2]-1)); if (d>0) d = (pos-centers[t]).norm2(); if (d<distance) { coefs = v; distance = d; index = t; } } } if (distance > 0) { // pos is outside of the fem mesh, find the nearest tetra // first let's find at least one tetra that is close, if not already found if (index >= 0) // we already have a close tetra, we need to look only for closer ones { cells.clear(); octree.findAllAround(cells, pos, sqrt(distance)*1.5); for (unsigned int ci = 0; ci < cells.size(); ++ci) { if (cells[ci] == cell) continue; // already processed this cell const sofa::helper::vector<int>& elems = cells[ci]->elems(); for (unsigned int e = 0; e < elems.size(); e++) { unsigned int t = elems[e]; double d = (pos-centers[t]).norm2(); if (d<distance) { coefs = bases[t] * (pos - in[tetras[t][0]]); distance = d; index = t; } } } } else { // failsafe case (should not happen...), to be sure we do a brute-force search for (unsigned int t = 0; t < tetras.size(); t++) { double d = (pos-centers[t]).norm2(); if (d<distance) { coefs = bases[t] * (pos - in[tetras[t][0]]); distance = d; index = t; } } } if (index >= 0) { //if (verbose >= 1) std::cout << "Surface vertex " << i << " mapped outside of tetra " << index << " with coefs " << coefs << std::endl; ++outside; } } if (index >= 0) { //std::cout << "Surface vertex " << i << " mapped from tetra " << index << " with coefs " << coefs << std::endl; d_map_i[i][0] = tetras[index][0]; d_map_f[i][0] = (float)(1-coefs[0]-coefs[1]-coefs[2]); d_map_i[i][1] = tetras[index][1]; d_map_f[i][1] = (float)(coefs[0]); d_map_i[i][2] = tetras[index][2]; d_map_f[i][2] = (float)(coefs[1]); d_map_i[i][3] = tetras[index][3]; d_map_f[i][3] = (float)(coefs[2]); } } LOGI( "Mapping done: %d - vertices outside of simulation mesh: %d", outside , out.size() ); } }
void SurfaceMesh::init(FEMMesh* inputMesh) { // elements <-> particles table #ifdef PARALLEL_GATHER { const int nbp = positions.size(); const int nbe = triangles.size(); const int nbBp = (nbp + BSIZE-1)/BSIZE; const int nbBe = (nbe + BSIZE-1)/BSIZE; // first find number of elements per particle std::vector<int> p_nbe; p_nbe.resize(nbp); for (int eindex = 0; eindex < nbe; ++eindex) for (int j = 0; j < 3; ++j) ++p_nbe[triangles[eindex][j]]; // then compute max value nbElemPerVertex = 0; for (int i=0;i<nbp;++i) if (p_nbe[i] > nbElemPerVertex) nbElemPerVertex = p_nbe[i]; // finally fill velems array velems.resize(nbBp*nbElemPerVertex*BSIZE); p_nbe.clear(); p_nbe.resize(nbp); for (int eindex = 0; eindex < nbe; ++eindex) for (int j = 0; j < 3; ++j) { int p = triangles[eindex][j]; int num = p_nbe[p]++; const int block = p / BSIZE; const int thread = p % BSIZE; velems[ block * (nbElemPerVertex * BSIZE) + num * BSIZE + thread ] = 1 + eindex; } } #endif // FEMMesh -> SurfaceMesh mapping if (inputMesh) { std::cout << "Creating mapping between simulation mesh \"" << inputMesh->filename << "\" and surface mesh \"" << filename << "\"..." << std::endl; static std::string input_filename; static sofa::helper::vector<Mat3x3d> bases; static sofa::helper::vector<Vec3d> centers; static Octree<Vec3d> octree; const TVecTetra& tetras = inputMesh->tetrahedra; const TVecCoord& in = inputMesh->positions; const TVecCoord& out = positions; map_i.resize(out.size()); map_f.resize(out.size()); if (input_filename != inputMesh->filename || bases.size() != tetras.size()) // we have to recompute the octree and bases { input_filename = inputMesh->filename; sofa::helper::vector< BBox<Vec3d> > bbox; bases.resize(tetras.size()); centers.resize(tetras.size()); bbox.resize(tetras.size()); std::cout << " Preparing tetrahedra" << std::endl; for (unsigned int t=0; t<tetras.size(); ++t) { Mat3x3d m, mt; m[0] = in[tetras[t][1]]-in[tetras[t][0]]; m[1] = in[tetras[t][2]]-in[tetras[t][0]]; m[2] = in[tetras[t][3]]-in[tetras[t][0]]; mt.transpose(m); bases[t].invert(mt); centers[t] = (in[tetras[t][0]]+in[tetras[t][1]]+in[tetras[t][2]]+in[tetras[t][3]])*0.25; bbox[t].add(tetras[t].begin(), tetras[t].end(), in); } std::cout << " Building octree" << std::endl; octree.init(bbox,8,8); } std::cout << " Processing vertices" << std::endl; int outside = 0; sofa::helper::vector<Octree<Vec3d>*> cells; for (unsigned int i=0;i<out.size();i++) { Vec3d pos = out[i]; Vec3d coefs; int index = -1; double distance = 1e10; Octree<Vec3d>* cell = octree.findNear(pos); if (cell) { const sofa::helper::vector<int>& elems = cell->elems(); for (unsigned int e = 0; e < elems.size(); e++) { unsigned int t = elems[e]; Vec3d v = bases[t] * (pos - in[tetras[t][0]]); double d = std::max(std::max(-v[0],-v[1]),std::max(-v[2],v[0]+v[1]+v[2]-1)); if (d>0) d = (pos-centers[t]).norm2(); if (d<distance) { coefs = v; distance = d; index = t; } } } if (distance > 0) { // pos is outside of the fem mesh, find the nearest tetra // first let's find at least one tetra that is close, if not already found if (index >= 0) // we already have a close tetra, we need to look only for closer ones { cells.clear(); octree.findAllAround(cells, pos, sqrt(distance)*1.5); for (unsigned int ci = 0; ci < cells.size(); ++ci) { if (cells[ci] == cell) continue; // already processed this cell const sofa::helper::vector<int>& elems = cells[ci]->elems(); for (unsigned int e = 0; e < elems.size(); e++) { unsigned int t = elems[e]; double d = (pos-centers[t]).norm2(); if (d<distance) { coefs = bases[t] * (pos - in[tetras[t][0]]); distance = d; index = t; } } } } else { // failsafe case (should not happen...), to be sure we do a brute-force search for (unsigned int t = 0; t < tetras.size(); t++) { double d = (pos-centers[t]).norm2(); if (d<distance) { coefs = bases[t] * (pos - in[tetras[t][0]]); distance = d; index = t; } } } if (index >= 0) { if (verbose >= 1) std::cout << "Surface vertex " << i << " mapped outside of tetra " << index << " with coefs " << coefs << std::endl; ++outside; } } if (index >= 0) { //std::cout << "Surface vertex " << i << " mapped from tetra " << index << " with coefs " << coefs << std::endl; map_i[i][0] = tetras[index][0]; map_f[i][0] = (float)(1-coefs[0]-coefs[1]-coefs[2]); map_i[i][1] = tetras[index][1]; map_f[i][1] = (float)(coefs[0]); map_i[i][2] = tetras[index][2]; map_f[i][2] = (float)(coefs[1]); map_i[i][3] = tetras[index][3]; map_f[i][3] = (float)(coefs[2]); } } std::cout << "Mapping done: " << outside << " / " << out.size() << " vertices outside of simulation mesh" << std::endl; } }