void ManifoldTriangleSetTopologyContainer::createEdgeSetArray() { if(!hasTriangles()) // this method should only be called when triangles exist { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::createEdgeSetArray] triangle array is empty." << std::endl; #endif createTriangleSetArray(); } if(hasEdges()) { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::createEdgeSetArray] edge array is not empty." << std::endl; #endif // clear edges and all shells that depend on edges EdgeSetTopologyContainer::clear(); if(hasEdgesInTriangle()) clearEdgesInTriangle(); if(hasTrianglesAroundEdge()) clearTrianglesAroundEdge(); } // create a temporary map to find redundant edges std::map<Edge, unsigned int> edgeMap; helper::WriteAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge; helper::ReadAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = d_triangle; for (unsigned int i=0; i<m_triangle.size(); ++i) { const Triangle &t = m_triangle[i]; for(unsigned int j=0; j<3; ++j) { const unsigned int v1 = t[(j+1)%3]; const unsigned int v2 = t[(j+2)%3]; const Edge e = ((v1<v2) ? Edge(v1,v2) : Edge(v2,v1)); const Edge real_e = Edge(v1,v2); if(edgeMap.find(e) == edgeMap.end()) { // edge not in edgeMap so create a new one const int edgeIndex = edgeMap.size(); edgeMap[e] = edgeIndex; m_edge.push_back(real_e); } } } }
const sofa::helper::vector< sofa::helper::vector<unsigned int> > &TriangleSetTopologyContainer::getTrianglesAroundEdgeArray() { if(!hasTrianglesAroundEdge()) // this method should only be called when the shell array exists { #ifndef NDEBUG sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundEdgeArray] triangle edge shell array is empty." << sendl; #endif createTrianglesAroundEdgeArray(); } return m_trianglesAroundEdge; }
const TriangleSetTopologyContainer::TrianglesAroundEdge& TriangleSetTopologyContainer::getTrianglesAroundEdge(EdgeID i) { if(!hasTrianglesAroundEdge()) // this method should only be called when the shell array exists { #ifndef NDEBUG sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundEdge] triangle edge shell array is empty." << sendl; #endif createTrianglesAroundEdgeArray(); } else if( i >= m_trianglesAroundEdge.size()) { #ifndef NDEBUG sout << "Error. [TriangleSetTopologyContainer::getTrianglesAroundEdge] index out of bounds." << sendl; #endif createTrianglesAroundEdgeArray(); } return m_trianglesAroundEdge[i]; }
sofa::helper::vector< unsigned int > &TriangleSetTopologyContainer::getTrianglesAroundEdgeForModification(const unsigned int i) { if(!hasTrianglesAroundEdge()) // this method should only be called when the shell array exists { #ifndef NDEBUG sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundEdgeForModification] triangle edge shell array is empty." << sendl; #endif createTrianglesAroundEdgeArray(); } if( i >= m_trianglesAroundEdge.size()) { #ifndef NDEBUG sout << "Error. [TriangleSetTopologyContainer::getTrianglesAroundEdgeForModification] index out of bounds." << sendl; #endif createTrianglesAroundEdgeArray(); } return m_trianglesAroundEdge[i]; }
void TriangleSetTopologyContainer::createTrianglesAroundEdgeArray () { if(!hasTriangles()) // this method should only be called when triangles exist { #ifndef NDEBUG sout << "Warning. [TriangleSetTopologyContainer::createTrianglesAroundEdgeArray] triangle array is empty." << sendl; #endif createTriangleSetArray(); } if(!hasEdges()) // this method should only be called when edges exist { #ifndef NDEBUG sout << "Warning. [TriangleSetTopologyContainer::createTrianglesAroundEdgeArray] edge array is empty." << sendl; #endif createEdgeSetArray(); } if(!hasEdgesInTriangle()) createEdgesInTriangleArray(); const unsigned int numTriangles = getNumberOfTriangles(); const unsigned int numEdges = getNumberOfEdges(); if(hasTrianglesAroundEdge()) { clearTrianglesAroundEdge(); } m_trianglesAroundEdge.resize( numEdges ); for (unsigned int i = 0; i < numTriangles; ++i) { // adding triangle i in the triangle shell of all edges for (unsigned int j=0; j<3; ++j) { m_trianglesAroundEdge[ m_edgesInTriangle[i][j] ].push_back( i ); } } }
bool TriangleSetTopologyContainer::checkTopology() const { #ifndef NDEBUG bool ret = true; helper::ReadAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = d_triangle; if (hasTrianglesAroundVertex()) { std::set <int> triangleSet; std::set<int>::iterator it; for (unsigned int i=0; i<m_trianglesAroundVertex.size(); ++i) { const sofa::helper::vector<unsigned int> &tvs = m_trianglesAroundVertex[i]; for (unsigned int j=0; j<tvs.size(); ++j) { bool check_triangle_vertex_shell = (m_triangle[tvs[j]][0]==i) || (m_triangle[tvs[j]][1]==i) || (m_triangle[tvs[j]][2]==i); if(!check_triangle_vertex_shell) { std::cout << "*** CHECK FAILED : check_triangle_vertex_shell, i = " << i << " , j = " << j << std::endl; ret = false; } it=triangleSet.find(tvs[j]); if(it == triangleSet.end()) { triangleSet.insert (tvs[j]); } } } if(triangleSet.size() != m_triangle.size()) { std::cout << "*** CHECK FAILED : check_triangle_vertex_shell, triangle are missing in m_trianglesAroundVertex" <<std::endl; ret = false; } } if (hasTrianglesAroundEdge()) { std::set <int> triangleSet; std::set<int>::iterator it; for (unsigned int i=0; i<m_trianglesAroundEdge.size(); ++i) { const sofa::helper::vector<unsigned int> &tes=m_trianglesAroundEdge[i]; for (unsigned int j=0; j<tes.size(); ++j) { bool check_triangle_edge_shell = (m_edgesInTriangle[tes[j]][0]==i) || (m_edgesInTriangle[tes[j]][1]==i) || (m_edgesInTriangle[tes[j]][2]==i); if(!check_triangle_edge_shell) { std::cout << "*** CHECK FAILED : check_triangle_edge_shell, i = " << i << " , j = " << j << std::endl; ret = false; } it=triangleSet.find(tes[j]); if(it == triangleSet.end()) { triangleSet.insert (tes[j]); } } } if(triangleSet.size() != m_triangle.size()) { std::cout << "*** CHECK FAILED : check_triangle_edge_shell, triangle are missing in m_trianglesAroundEdge" <<std::endl; ret = false; } } return ret && EdgeSetTopologyContainer::checkTopology(); #else return true; #endif }
void TriangleSetTopologyContainer::createElementsOnBorder() { if(!hasTrianglesAroundEdge()) // Use the trianglesAroundEdgeArray. Should check if it is consistent { #ifndef NDEBUG std::cout << "Warning. [TriangleSetTopologyContainer::createElementsOnBorder] Triangle edge shell array is empty." << std::endl; #endif createTrianglesAroundEdgeArray(); } if(!m_trianglesOnBorder.empty()) m_trianglesOnBorder.clear(); if(!m_edgesOnBorder.empty()) m_edgesOnBorder.clear(); if(!m_pointsOnBorder.empty()) m_pointsOnBorder.clear(); const unsigned int nbrEdges = getNumberOfEdges(); bool newTriangle = true; bool newEdge = true; bool newPoint = true; helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge; for (unsigned int i = 0; i < nbrEdges; i++) { if (m_trianglesAroundEdge[i].size() == 1) // I.e this edge is on a border { // --- Triangle case --- for (unsigned int j = 0; j < m_trianglesOnBorder.size(); j++) // Loop to avoid duplicated indices { if (m_trianglesOnBorder[j] == m_trianglesAroundEdge[i][0]) { newTriangle = false; break; } } if(newTriangle) // If index doesn't already exist, add it to the list of triangles On border. { m_trianglesOnBorder.push_back (m_trianglesAroundEdge[i][0]); } // --- Edge case --- for (unsigned int j = 0; j < m_edgesOnBorder.size(); j++) // Loop to avoid duplicated indices { if (m_edgesOnBorder[j] == i) { newEdge = false; break; } } if(newEdge) // If index doesn't already exist, add it to the list of edges On border. { m_edgesOnBorder.push_back (i); } // --- Point case --- PointID firstVertex = m_edge[i][0]; for (unsigned int j = 0; j < m_pointsOnBorder.size(); j++) // Loop to avoid duplicated indices { if (m_pointsOnBorder[j] == firstVertex) { newPoint = false; break; } } if(newPoint) // If index doesn't already exist, add it to the list of points On border. { m_pointsOnBorder.push_back (firstVertex); } newTriangle = true; //reinitialize tests variables newEdge = true; newPoint = true; } } }
int ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge(EdgeID edgeIndex, TriangleID triangleIndex) { if(!hasTrianglesAroundEdge()) // this method should only be called when the shell array exists { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge] Triangle edge shell array is empty." << std::endl; #endif createTrianglesAroundEdgeArray(); } if (edgeIndex >= m_trianglesAroundEdge.size()) { #ifndef NDEBUG std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge] Edge Index out of bounds." << std::endl; #endif return -2; } if (triangleIndex >= (d_triangle.getValue()).size()) { #ifndef NDEBUG std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getNextTrianglesAroundVertex] Triangle index out of bounds." << std::endl; #endif return -2; } if (m_trianglesAroundEdge[edgeIndex].size() > 2) { #ifndef NDEBUG std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge] The mapping is not manifold."; std::cout << "There are more than 2 triangles adjacents to the Edge: " << edgeIndex << std::endl; #endif return -2; } else if (m_trianglesAroundEdge[edgeIndex].size() == 1) { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge] No triangle has been returned. Input Edge belongs to the border." << std::endl; #endif return -1; } else if (m_trianglesAroundEdge[edgeIndex][0] == triangleIndex) { return m_trianglesAroundEdge[edgeIndex][1]; } else if (m_trianglesAroundEdge[edgeIndex][1] == triangleIndex) { return m_trianglesAroundEdge[edgeIndex][0]; } #ifndef NDEBUG std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getOppositeTrianglesAroundEdge] No Triangle has been returned." << std::endl; #endif return -2; }
void ManifoldTriangleSetTopologyContainer::createTrianglesAroundEdgeArray() { if(!hasTriangles()) // this method should only be called when triangles exist { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::createTrianglesAroundEdgeArray] Triangle array is empty." << std::endl; #endif createTriangleSetArray(); } if(!hasEdges()) // this method should only be called when edges exist { #ifndef NDEBUG std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::createTrianglesAroundEdgeArray] Edge array is empty." << std::endl; #endif createEdgeSetArray(); } if(!hasEdgesInTriangle()) createEdgesInTriangleArray(); if(hasTrianglesAroundEdge()) clearTrianglesAroundEdge(); //Number of different elements needed for this function const unsigned int nbrEdges = getNumberOfEdges(); const unsigned int nbrTriangles = getNumberOfTriangles(); //Temporary objects Triangle vertexTriangle; int cpt; int firstVertex; int vertexInTriangle; //Temporary containers std::multimap<unsigned int, unsigned int> map_edgesInTriangle; std::multimap<unsigned int, unsigned int>::iterator it; std::pair< std::multimap <unsigned int, unsigned int>::iterator, std::multimap <unsigned int, unsigned int>::iterator> pair_equal_range; helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge; helper::ReadAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = d_triangle; m_trianglesAroundEdge.resize(nbrEdges); for (unsigned int triangleIndex = 0; triangleIndex < nbrTriangles; ++triangleIndex) { // adding triangle i in the triangle shell of all edges for (unsigned int indexEdge = 0; indexEdge<3 ; ++indexEdge) { map_edgesInTriangle.insert(std::pair < unsigned int, unsigned int> (m_edgesInTriangle[triangleIndex][indexEdge], triangleIndex)); } } for (unsigned int indexEdge = 0; indexEdge < nbrEdges; indexEdge++) { cpt = map_edgesInTriangle.count(indexEdge); if (cpt > 2) { #ifndef NDEBUG std::cout << "Error. [ManifoldTriangleSetTopologyContainer::createTrianglesAroundEdgeArray] The mapping is not manifold."; std::cout << "There are more than 2 triangles adjacents to the Edge: " << indexEdge << std::endl; #endif //Even if this structure is not Manifold, we chosed to fill the shell with all the triangles: pair_equal_range = map_edgesInTriangle.equal_range(indexEdge); for (it = pair_equal_range.first; it != pair_equal_range.second; ++it) m_trianglesAroundEdge[indexEdge].push_back((*it).second); } else if (cpt == 1) { it = map_edgesInTriangle.find(indexEdge); m_trianglesAroundEdge[indexEdge].push_back((*it).second); } else if (cpt == 2) { pair_equal_range = map_edgesInTriangle.equal_range(indexEdge); it = pair_equal_range.first; firstVertex = m_edge[indexEdge][0]; vertexTriangle = m_triangle[(*it).second]; vertexInTriangle = getVertexIndexInTriangle (vertexTriangle, firstVertex); if ((unsigned int)m_edge[indexEdge][1] == (unsigned int)vertexTriangle[(vertexInTriangle+1)%3]) { m_trianglesAroundEdge[indexEdge].push_back((*it).second); it++; m_trianglesAroundEdge[indexEdge].push_back((*it).second); } else { it++; m_trianglesAroundEdge[indexEdge].push_back((*it).second); it--; m_trianglesAroundEdge[indexEdge].push_back((*it).second); } } } }