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);
            }
        }
    }
}