void TriangleSetTopologyContainer::createTrianglesAroundVertexArray ()
{
    if(!hasTriangles()) // this method should only be called when triangles exist
    {
#ifndef NDEBUG
        sout << "Warning. [TriangleSetTopologyContainer::createTrianglesAroundVertexArray] triangle array is empty." << sendl;
#endif
        createTriangleSetArray();
    }

    if(hasTrianglesAroundVertex())
    {
        clearTrianglesAroundVertex();
    }

    m_trianglesAroundVertex.resize( getNbPoints() );
    helper::ReadAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = d_triangle;

    for (unsigned int i = 0; i < m_triangle.size(); ++i)
    {
        // adding edge i in the edge shell of both points
        for (unsigned int j=0; j<3; ++j)
            m_trianglesAroundVertex[ m_triangle[i][j]  ].push_back( i );
    }
}
int TriangleSetTopologyContainer::getTriangleIndex(PointID v1, PointID v2, PointID v3)
{
    if(!hasTrianglesAroundVertex())
        createTrianglesAroundVertexArray();

    sofa::helper::vector<unsigned int> set1 = getTrianglesAroundVertex(v1);
    sofa::helper::vector<unsigned int> set2 = getTrianglesAroundVertex(v2);
    sofa::helper::vector<unsigned int> set3 = getTrianglesAroundVertex(v3);

    sort(set1.begin(), set1.end());
    sort(set2.begin(), set2.end());
    sort(set3.begin(), set3.end());

    // The destination vector must be large enough to contain the result.
    sofa::helper::vector<unsigned int> out1(set1.size()+set2.size());
    sofa::helper::vector<unsigned int>::iterator result1;
    result1 = std::set_intersection(set1.begin(),set1.end(),set2.begin(),set2.end(),out1.begin());
    out1.erase(result1,out1.end());

    sofa::helper::vector<unsigned int> out2(set3.size()+out1.size());
    sofa::helper::vector<unsigned int>::iterator result2;
    result2 = std::set_intersection(set3.begin(),set3.end(),out1.begin(),out1.end(),out2.begin());
    out2.erase(result2,out2.end());

#ifndef NDEBUG
    if(out2.size() > 1)
        sout << "Warning. [TriangleSetTopologyContainer::getTriangleIndex] more than one triangle found" << sendl;
#endif

    if (out2.size()==1)
        return (int) (out2[0]);
    else
        return -1;
}
const sofa::helper::vector< sofa::helper::vector<unsigned int> > &TriangleSetTopologyContainer::getTrianglesAroundVertexArray()
{
    if(!hasTrianglesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundVertexArray] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    return m_trianglesAroundVertex;
}
const TriangleSetTopologyContainer::VecTriangleID TriangleSetTopologyContainer::getElementAroundElements(VecTriangleID elems)
{
    VecTriangleID elemAll;
    VecTriangleID elemTmp;

    if (!hasTrianglesAroundVertex())
    {
#ifndef NDEBUG
        serr << "Warning. [TriangleSetTopologyContainer::getElementAroundElements] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    for (unsigned int i = 0; i <elems.size(); ++i) // for each triangleId of input vector
    {
        VecTriangleID elemTmp2 = this->getElementAroundElement(elems[i]);

        elemTmp.insert(elemTmp.end(), elemTmp2.begin(), elemTmp2.end());
    }

    for (unsigned int i = 0; i<elemTmp.size(); ++i) // for each Triangle Id found
    {
        bool find = false;
        TriangleID id = elemTmp[i];

        for (unsigned int j = 0; j<elems.size(); ++j) // check no redundancy with input vector
            if (id == elems[j])
            {
                find = true;
                break;
            }

        if (!find)
        {
            for (unsigned int j = 0; j<elemAll.size(); ++j) // check no redundancy in output vector
                if (id == elemAll[j])
                {
                    find = true;
                    break;
                }
        }

        if (!find)
            elemAll.push_back(id);
    }

    return elemAll;
}
const TriangleSetTopologyContainer::TrianglesAroundVertex& TriangleSetTopologyContainer::getTrianglesAroundVertex(PointID i)
{
    if(!hasTrianglesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundVertex] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }
    else if( i >= m_trianglesAroundVertex.size())
    {
#ifndef NDEBUG
        sout << "Error. [TriangleSetTopologyContainer::getTrianglesAroundVertex] index out of bounds." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    return m_trianglesAroundVertex[i];
}
sofa::helper::vector< unsigned int > &TriangleSetTopologyContainer::getTrianglesAroundVertexForModification(const unsigned int i)
{
    if(!hasTrianglesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        sout << "Warning. [TriangleSetTopologyContainer::getTrianglesAroundVertexForModification] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    if( i >= m_trianglesAroundVertex.size())
    {
#ifndef NDEBUG
        sout << "Error. [TriangleSetTopologyContainer::getTrianglesAroundVertexForModification] index out of bounds." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    return m_trianglesAroundVertex[i];
}
const TriangleSetTopologyContainer::VecTriangleID TriangleSetTopologyContainer::getElementAroundElement(TriangleID elem)
{
    VecTriangleID elems;

    if (!hasTrianglesAroundVertex())
    {
#ifndef NDEBUG
        serr << "Warning. [TriangleSetTopologyContainer::getElementAroundElement] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    Triangle the_tri = this->getTriangle(elem);

    for(unsigned int i = 0; i<3; ++i) // for each node of the triangle
    {
        TrianglesAroundVertex triAV = this->getTrianglesAroundVertex(the_tri[i]);

        for (unsigned int j = 0; j<triAV.size(); ++j) // for each triangle around the node
        {
            bool find = false;
            TriangleID id = triAV[j];

            if (id == elem)
                continue;

            for (unsigned int k = 0; k<elems.size(); ++k) // check no redundancy
                if (id == elems[k])
                {
                    find = true;
                    break;
                }

            if (!find)
                elems.push_back(id);
        }
    }
    return elems;
}
const TriangleSetTopologyContainer::VecTriangleID TriangleSetTopologyContainer::getConnectedElement(TriangleID elem)
{
    if(!hasTrianglesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        serr << "Warning. [TriangleSetTopologyContainer::getConnectedElement] triangle vertex shell array is empty." << sendl;
#endif
        createTrianglesAroundVertexArray();
    }

    VecTriangleID elemAll;
    VecTriangleID elemOnFront, elemPreviousFront, elemNextFront;
    bool end = false;
    size_t cpt = 0;
    size_t nbr = this->getNbTriangles();

    // init algo
    elemAll.push_back(elem);
    elemOnFront.push_back(elem);
    elemPreviousFront.clear();
    cpt++;

    while (!end && cpt < nbr)
    {
        // First Step - Create new region
        elemNextFront = this->getElementAroundElements(elemOnFront); // for each triangleID on the propagation front
        // Second Step - Avoid backward direction
        for (unsigned int i = 0; i<elemNextFront.size(); ++i)
        {
            bool find = false;
            TriangleID id = elemNextFront[i];

            for (unsigned int j = 0; j<elemAll.size(); ++j)
                if (id == elemAll[j])
                {
                    find = true;
                    break;
                }

            if (!find)
            {
                elemAll.push_back(id);
                elemPreviousFront.push_back(id);
            }
        }
        // cpt for connexity
        cpt +=elemPreviousFront.size();

        if (elemPreviousFront.empty())
        {
            end = true;
#ifndef NDEBUG
            serr << "Loop for computing connexity has reach end." << sendl;
#endif
        }

        // iterate
        elemOnFront = elemPreviousFront;
        elemPreviousFront.clear();
    }
    return elemAll;
}
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
}
int ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex(PointID vertexIndex, TriangleID triangleIndex)
{

    if(!hasTrianglesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex] Triangle vertex shell array is empty." << std::endl;
#endif

        createTrianglesAroundVertexArray();
    }


    if( vertexIndex >= m_trianglesAroundVertex.size())
    {
#ifndef NDEBUG
        std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex] Vertex index out of bounds." << std::endl;
#endif
        return -2;
    }

    if( triangleIndex >= (d_triangle.getValue()).size())
    {
#ifndef NDEBUG
        std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex] Triangle index out of bounds." << std::endl;
#endif
        return -2;
    }


    unsigned int nbrTriangle = m_trianglesAroundVertex[vertexIndex].size();

    for (unsigned int i = 0; i < nbrTriangle; ++i)
    {

        if ( m_trianglesAroundVertex[vertexIndex][i] == triangleIndex)
        {
            if ( i == 0)
            {
                Triangle triangle1 = getTriangleArray()[m_trianglesAroundVertex[vertexIndex][nbrTriangle-1]];
                Triangle triangle2 = getTriangleArray()[m_trianglesAroundVertex[vertexIndex][0]];

                if ( triangle1[(getVertexIndexInTriangle(triangle1, vertexIndex)+2)%3] != triangle2[(getVertexIndexInTriangle(triangle2, vertexIndex)+1)%3])
                {
#ifndef NDEBUG
                    std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex] No Triangle has been found. Input Triangle must belong to the border." << std::endl;
#endif
                    return -1;
                }
                else
                {
                    return m_trianglesAroundVertex[vertexIndex][nbrTriangle-1];
                }

            }
            else
            {
                return m_trianglesAroundVertex[vertexIndex][i-1];
            }
        }

    }


#ifndef NDEBUG
    std::cout << "Error. [ManifoldTriangleSetTopologyContainer::getPreviousTrianglesAroundVertex] No Triangle has been returned." << std::endl;
#endif
    return -2;
}
void ManifoldTriangleSetTopologyContainer::createTrianglesAroundVertexArray ()
{
    if(!hasTriangles()) // this method should only be called when triangles exist
    {
#ifndef NDEBUG
        std::cout << "Warning. [ManifoldTriangleSetTopologyContainer::createTrianglesAroundVertexArray] triangle array is empty." << std::endl;
#endif

        createTriangleSetArray();
    }

    if(hasTrianglesAroundVertex())
    {
        clearTrianglesAroundVertex();
    }

    //Number of different elements needed for this function
    const unsigned int nbrVertices = getNbPoints();
    const unsigned int nbrTriangles = getNumberOfTriangles();

    //Temporary objects
    Triangle vertexTriangle;
    unsigned int cpt;
    unsigned int firstVertex;

    //Temporary containers
    sofa::helper::vector< std::map<unsigned int, unsigned int> > map_Triangles;
    sofa::helper::vector< std::map<unsigned int, unsigned int> > map_NextVertex;
    sofa::helper::vector< std::map<unsigned int, unsigned int> > map_PreviousVertex;

    std::map<unsigned int, unsigned int>::iterator it1;
    std::map<unsigned int, unsigned int>::iterator it2;

    m_trianglesAroundVertex.resize(nbrVertices);
    map_Triangles.resize(nbrVertices);
    map_NextVertex.resize(nbrVertices);
    map_PreviousVertex.resize(nbrVertices);

    /*	Creation of the differents maps: For each vertex i of each triangles:
     - map_Triangles: key = vertex i+1, value = index triangle
     - map_Nextvertex: key = vertex i+1, value = vertex i+2
     - map_PreviousVertex: key = vertex i+2, value = vertex i+1	*/
    for (unsigned int triangleIndex = 0; triangleIndex < nbrTriangles; ++triangleIndex)
    {
        vertexTriangle = getTriangleArray()[triangleIndex];

        for (unsigned int i=0; i<3; ++i)
        {
            map_Triangles[vertexTriangle[i]].insert(std::pair<unsigned int,unsigned int> (vertexTriangle[(i+1)%3], triangleIndex)); //multi

            map_NextVertex[vertexTriangle[i]].insert(std::pair<unsigned int,unsigned int> (vertexTriangle[(i+1)%3], vertexTriangle[(i+2)%3]));
            map_PreviousVertex[vertexTriangle[i]].insert(std::pair<unsigned int,unsigned int> (vertexTriangle[(i+2)%3], vertexTriangle[(i+1)%3]));
        }
    }

    // General loop for m_trianglesAroundVertex creation
    for (unsigned int vertexIndex = 0; vertexIndex < nbrVertices; ++vertexIndex)
    {
        it1 = map_NextVertex[vertexIndex].begin();
        firstVertex = (*it1).first;

        for (it1 = map_NextVertex[vertexIndex].begin(); it1 != map_NextVertex[vertexIndex].end(); ++it1)
        {
            it2 = map_PreviousVertex[vertexIndex].find((*it1).first);

            if (it2 == map_PreviousVertex[vertexIndex].end()) //it2 didn't find the it1 correspondant element in his map, means it's a border
            {
                firstVertex = (*it1).first;
                break;
            }//else we are not on a border. we keep the initialised value for firstVertex
        }
        m_trianglesAroundVertex[vertexIndex].push_back(map_Triangles[vertexIndex][firstVertex]);
        cpt=1;

        for (unsigned int i = 1; i < map_NextVertex[vertexIndex].size(); ++i)
        {
            it2 = map_NextVertex[vertexIndex].find(firstVertex);

            if (((*it2).first == firstVertex) && (it2 == map_NextVertex[vertexIndex].end()))
            {
                // Contour has been done without reaching the end of the map
                break;
            }
            firstVertex = (*it2).second;

            m_trianglesAroundVertex[vertexIndex].push_back(map_Triangles[vertexIndex][firstVertex]);
            cpt++;
        }

        if (cpt != map_Triangles[vertexIndex].size())
        {
#ifndef NDEBUG
            std::cout << "Error. [ManifoldTriangleSetTopologyContainer::createEdgesAroundVertexArray] The mapping is not manifold.";
            std::cout << "There is a wrong connection between triangles adjacent to the vertex: "<< vertexIndex << std::endl;
#endif
        }
    }
    map_Triangles.clear();
    map_NextVertex.clear();
    map_PreviousVertex.clear();
}