void TriangleSetTopologyModifier::removeTriangles(sofa::helper::vector< unsigned int >& triangles,
							const bool removeIsolatedEdges,
							const bool removeIsolatedPoints)
      {
	helper::ReadAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = m_container->d_triangle;
	for (unsigned int i = 0; i < triangles.size(); i++)
            {
              if( triangles[i] >= m_triangle.size())
                {
                  std::cout << "Error: TriangleSetTopologyModifier::removeTriangles: Triangle: "<< triangles[i] <<" is out of bound" << std::endl;
                  return;
                }
            }


          if (removeTrianglesPreconditions(triangles)) // Test if the topology will still fullfil the conditions if these triangles are removed.
            {
              /// add the topological changes in the queue
              removeTrianglesWarning(triangles);
              // inform other objects that the triangles are going to be removed
              propagateTopologicalChanges();
              // now destroy the old triangles.
              removeTrianglesProcess(  triangles ,removeIsolatedEdges, removeIsolatedPoints);

              m_container->checkTopology();
            }
          else
            {
              std::cout << " TriangleSetTopologyModifier::removeItems(), preconditions for removal are not fullfil. " << std::endl;
            }

      }
      void TriangleSetTopologyModifier::movePointsProcess (const sofa::helper::vector <unsigned int>& id,
							   const sofa::helper::vector< sofa::helper::vector< unsigned int > >& ancestors,
							   const sofa::helper::vector< sofa::helper::vector< double > >& coefs,
							   const bool moveDOF)
      {
	(void)moveDOF;
	unsigned int nbrVertex = id.size();
	bool doublet;
	sofa::helper::vector< unsigned int > trianglesAroundVertex2Move;
	sofa::helper::vector< Triangle > trianglesArray;


	// Step 1/4 - Creating trianglesAroundVertex to moved due to moved points:
	for (unsigned int i = 0; i<nbrVertex; ++i)
	{
	  const sofa::helper::vector <unsigned int>& trianglesAroundVertex = m_container->getTrianglesAroundVertex( id[i] );

	  for (unsigned int j = 0; j<trianglesAroundVertex.size(); ++j)
	  {
	    doublet = false;
	
	    for (unsigned int k =0; k<trianglesAroundVertex2Move.size(); ++k) //Avoid double
	    {
	      if (trianglesAroundVertex2Move[k] == trianglesAroundVertex[j])
	      {
		doublet = true;
		break;
	      }
	    }
	    
	    if(!doublet)
	      trianglesAroundVertex2Move.push_back (trianglesAroundVertex[j]);
	    
	  }
	}
	
	std::sort( trianglesAroundVertex2Move.begin(), trianglesAroundVertex2Move.end(), std::greater<unsigned int>() );


	// Step 2/4 - Create event to delete all elements before moving and propagate it:
	TrianglesMoved_Removing *ev1 = new TrianglesMoved_Removing (trianglesAroundVertex2Move);
	this->addTopologyChange(ev1);
	propagateTopologicalChanges();


	// Step 3/4 - Physically move all dof:
	PointSetTopologyModifier::movePointsProcess (id, ancestors, coefs);
	
	
	// Step 4/4 - Create event to recompute all elements concerned by moving and propagate it:

	// Creating the corresponding array of Triangles for ancestors
	for (unsigned int i = 0; i<trianglesAroundVertex2Move.size(); i++)
	  trianglesArray.push_back (m_container->getTriangleArray()[ trianglesAroundVertex2Move[i] ]);

	TrianglesMoved_Adding *ev2 = new TrianglesMoved_Adding (trianglesAroundVertex2Move, trianglesArray);
	this->addTopologyChange(ev2); // This event should be propagated with global workflow
      }
void HexahedronSetTopologyModifier::renumberPoints(const sofa::helper::vector<unsigned int> &index,
        const sofa::helper::vector<unsigned int> &inv_index)
{
    /// add the topological changes in the queue
    renumberPointsWarning(index, inv_index);
    // inform other objects that the triangles are going to be removed
    propagateTopologicalChanges();
    // now renumber the points
    renumberPointsProcess(index, inv_index);

    m_container->checkTopology();
}
void HexahedronSetTopologyModifier::removeHexahedra(const sofa::helper::vector< unsigned int >& hexahedraIds)
{
    sofa::helper::vector<unsigned int> hexahedraIds_filtered;
    for (unsigned int i = 0; i < hexahedraIds.size(); i++)
    {
        if( hexahedraIds[i] >= m_container->getNumberOfHexahedra())
            msg_error() << "Unable to remove the hexahedra: "<< hexahedraIds[i] <<" its index is out of bound." ;
        else
            hexahedraIds_filtered.push_back(hexahedraIds[i]);
    }

    // add the topological changes in the queue
    removeHexahedraWarning(hexahedraIds_filtered);
    // inform other objects that the hexa are going to be removed
    propagateTopologicalChanges();
    // now destroy the old hexahedra.
    removeHexahedraProcess(hexahedraIds_filtered ,true);

    m_container->checkTopology();
}
void QuadSetTopologyModifier::removeQuads(const sofa::helper::vector< unsigned int >& quadIds,
        const bool removeIsolatedEdges,
        const bool removeIsolatedPoints)
{
    sofa::helper::vector<unsigned int> quadIds_filtered;
    for (unsigned int i = 0; i < quadIds.size(); i++)
    {
        if( quadIds[i] >= m_container->getNumberOfQuads())
            std::cout << "Error: QuadSetTopologyModifier::removeQuads: quad: "<< quadIds[i] <<" is out of bound and won't be removed." << std::endl;
        else
            quadIds_filtered.push_back(quadIds[i]);
    }

    /// add the topological changes in the queue
    removeQuadsWarning(quadIds_filtered);
    // inform other objects that the quads are going to be removed
    propagateTopologicalChanges();
    // now destroy the old quads.
    removeQuadsProcess( quadIds_filtered, removeIsolatedEdges, removeIsolatedPoints);

    m_container->checkTopology();
}
      void TriangleSetTopologyModifier::removeTrianglesProcess(const sofa::helper::vector<unsigned int> &indices,
							       const bool removeIsolatedEdges,
							       const bool removeIsolatedPoints)
      {

	if(!m_container->hasTriangles()) // this method should only be called when triangles exist
	{
#ifndef NDEBUG
	  sout << "Error. [TriangleSetTopologyModifier::removeTrianglesProcess] triangle array is empty." << endl;
#endif
	  return;
	}


	if(m_container->hasEdges() && removeIsolatedEdges)
	{

	  if(!m_container->hasEdgesInTriangle())
	    m_container->createEdgesInTriangleArray();

	  if(!m_container->hasTrianglesAroundEdge())
	    m_container->createTrianglesAroundEdgeArray();
	}

	if(removeIsolatedPoints)
	{

	  if(!m_container->hasTrianglesAroundVertex())
	    m_container->createTrianglesAroundVertexArray();
	}

	sofa::helper::vector<unsigned int> edgeToBeRemoved;
	sofa::helper::vector<unsigned int> vertexToBeRemoved;
	helper::WriteAccessor< Data< sofa::helper::vector<Triangle> > > m_triangle = m_container->d_triangle;

	unsigned int lastTriangle = m_container->getNumberOfTriangles() - 1;
	for(unsigned int i = 0; i<indices.size(); ++i, --lastTriangle)
	{
	  Triangle &t = m_triangle[ indices[i] ];
	  Triangle &q = m_triangle[ lastTriangle ];

	  if(m_container->hasTrianglesAroundVertex())
	  {
	    for(unsigned int j=0; j<3; ++j)
	    {
	      sofa::helper::vector< unsigned int > &shell = m_container->m_trianglesAroundVertex[ t[j] ];
	      shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
	      if(removeIsolatedPoints && shell.empty())
		vertexToBeRemoved.push_back(t[j]);
	    }
	  }

	  if(m_container->hasTrianglesAroundEdge())
	  {
	    for(unsigned int j=0; j<3; ++j)
	    {
	      sofa::helper::vector< unsigned int > &shell = m_container->m_trianglesAroundEdge[ m_container->m_edgesInTriangle[indices[i]][j]];
	      shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
	      if(removeIsolatedEdges && shell.empty())
		edgeToBeRemoved.push_back(m_container->m_edgesInTriangle[indices[i]][j]);
	    }
	  }

	  if(indices[i] < lastTriangle)
	  {

	    if(m_container->hasTrianglesAroundVertex())
	    {

	      for(unsigned int j=0; j<3; ++j)
	      {
		sofa::helper::vector< unsigned int > &shell = m_container->m_trianglesAroundVertex[ q[j] ];
		replace(shell.begin(), shell.end(), lastTriangle, indices[i]);
	      }
	    }

	    if(m_container->hasTrianglesAroundEdge())
	    {

	      for(unsigned int j=0; j<3; ++j)
	      {
		sofa::helper::vector< unsigned int > &shell = m_container->m_trianglesAroundEdge[ m_container->m_edgesInTriangle[lastTriangle][j]];
		replace(shell.begin(), shell.end(), lastTriangle, indices[i]);
	      }
	    }
	  }

	  // removes the edgesInTriangles from the edgesInTrianglesArray
	  if(m_container->hasEdgesInTriangle())
	  {

	    m_container->m_edgesInTriangle[ indices[i] ] = m_container->m_edgesInTriangle[ lastTriangle ]; // overwriting with last valid value.
	    m_container->m_edgesInTriangle.resize( lastTriangle ); // resizing to erase multiple occurence of the triangle.
	  }

	  // removes the triangle from the triangleArray
	  m_triangle[ indices[i] ] = m_triangle[ lastTriangle ]; // overwriting with last valid value.
	  m_triangle.resize( lastTriangle ); // resizing to erase multiple occurence of the triangle.
	}

	removeTrianglesPostProcessing(edgeToBeRemoved, vertexToBeRemoved); // Arrange the current topology.

	if(!edgeToBeRemoved.empty())
	{
	  /// warn that edges will be deleted
	  removeEdgesWarning(edgeToBeRemoved);
	  propagateTopologicalChanges();
	  /// actually remove edges without looking for isolated vertices
	  removeEdgesProcess(edgeToBeRemoved, false);
	}

	if(!vertexToBeRemoved.empty())
	{
	  removePointsWarning(vertexToBeRemoved);
	  /// propagate to all components
	  propagateTopologicalChanges();
	  removePointsProcess(vertexToBeRemoved);
	}

/*
#ifndef NDEBUG // TO BE REMOVED WHEN SURE.
	Debug();
#endif
*/
      }
void ManifoldTriangleSetTopologyModifier::addRemoveTriangles (const unsigned int nTri2Add,
        const sofa::helper::vector< Triangle >& triangles2Add,
        const sofa::helper::vector< unsigned int >& trianglesIndex2Add,
        const sofa::helper::vector< sofa::helper::vector< unsigned int > > & ancestors,
        const sofa::helper::vector< sofa::helper::vector< double > >& baryCoefs,
        sofa::helper::vector< unsigned int >& trianglesIndex2remove)
{
    // I - Create ROI to remesh: step 1/2
    sofa::helper::vector <unsigned int> vertexROI2Remesh;

    // Look for every vertices concerned by the modifications
    for (unsigned int i = 0; i <trianglesIndex2remove.size(); i++)
    {
        Triangle new_tri = m_container->getTriangleArray()[ trianglesIndex2remove[i] ];
        for (unsigned int j = 0; j <3; j++)
        {
            vertexROI2Remesh.push_back (new_tri[j]); // these index vertex could change due to removing point.... TODO??
        }
    }


    // II - Add the triangles
    for (unsigned int i = 0; i <nTri2Add; i++)
    {
        // Use the most low level function to add triangle. I.e without any preliminary test.
        TriangleSetTopologyModifier::addTriangleProcess (triangles2Add[i]);
    }

    // Warn for the creation of all the triangles registered to be created
    TriangleSetTopologyModifier::addTrianglesWarning (nTri2Add, triangles2Add, trianglesIndex2Add, ancestors, baryCoefs);


    // III - removes the triangles

    // add the topological changes in the queue
    TriangleSetTopologyModifier::removeTrianglesWarning (trianglesIndex2remove);

    // inform other objects that the triangles are going to be removed
    propagateTopologicalChanges();

    // now destroy the old triangles.
    TriangleSetTopologyModifier::removeTrianglesProcess (trianglesIndex2remove ,true, true);


    // IV - Create ROI to remesh: step 2/2

    sofa::helper::vector <unsigned int> trianglesFinalList;
    trianglesFinalList = trianglesIndex2Add;

    std::sort( trianglesIndex2remove.begin(), trianglesIndex2remove.end(), std::greater<unsigned int>() );

    // Update the list of triangles (removing triangles change the index order)
    for (unsigned int i = 0; i<trianglesIndex2remove.size(); i++)
    {
        trianglesFinalList[trianglesFinalList.size()-1-i] = trianglesIndex2remove[i];
    }

    // Look for every vertices concerned by the modifications
    for (unsigned int i = 0; i <nTri2Add; i++)
    {
        Triangle new_tri = m_container->getTriangleArray()[ trianglesFinalList[i] ];
        for (unsigned int j = 0; j <3; j++)
        {
            vertexROI2Remesh.push_back (new_tri[j]);
        }
    }


    reorderingTopologyOnROI (vertexROI2Remesh);

    bool topo = m_container->checkTopology();
    if (!topo) //IN DEVELOPMENT (probably only in NDEBUG
    {
        std::cout <<"WARNING. [ManifoldTriangleSetTopologyModifier::addRemoveTriangles] The topology wasn't manifold after reordering the ROI. Reordering the whole triangulation." << std::endl;

        sofa::helper::vector <unsigned int> allmesh;
        for (int i = 0; i <m_container->getNbPoints(); i++)
            allmesh.push_back (i);

        reorderingTopologyOnROI (allmesh);
    }

#ifndef NDEBUG
    if(!m_container->checkTopology())
        sout << "Error. [ManifoldTriangleSetTopologyModifier::addRemoveTriangles] The topology is not any more Manifold." << endl;
#endif
}
void HexahedronSetTopologyModifier::removeHexahedraProcess( const sofa::helper::vector<unsigned int> &indices,
        const bool removeIsolatedItems)
{
    if(!m_container->hasHexahedra())
        return;

    bool removeIsolatedVertices = removeIsolatedItems && removeIsolated.getValue();
    bool removeIsolatedEdges = removeIsolatedItems && m_container->hasEdges();
    bool removeIsolatedQuads = removeIsolatedItems && m_container->hasQuads();

    if(removeIsolatedVertices)
    {
        if(!m_container->hasHexahedraAroundVertex())
            m_container->createHexahedraAroundVertexArray();
    }

    if(removeIsolatedEdges)
    {
        if(!m_container->hasHexahedraAroundEdge())
            m_container->createHexahedraAroundEdgeArray();
    }

    if(removeIsolatedQuads)
    {
        if(!m_container->hasHexahedraAroundQuad())
            m_container->createHexahedraAroundQuadArray();
    }

    sofa::helper::vector<unsigned int> quadToBeRemoved;
    sofa::helper::vector<unsigned int> edgeToBeRemoved;
    sofa::helper::vector<unsigned int> vertexToBeRemoved;

    unsigned int lastHexahedron = m_container->getNumberOfHexahedra() - 1;

    helper::WriteAccessor< Data< sofa::helper::vector<Hexahedron> > > m_hexahedron = m_container->d_hexahedron;

    for(unsigned int i=0; i<indices.size(); ++i, --lastHexahedron)
    {
        const Hexahedron &t = m_hexahedron[ indices[i] ];
        const Hexahedron &h = m_hexahedron[ lastHexahedron ];

        if(m_container->hasHexahedraAroundVertex())
        {
            for(unsigned int v=0; v<8; ++v)
            {
                sofa::helper::vector< unsigned int > &shell = m_container->m_hexahedraAroundVertex[ t[v] ];
                shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
                if(removeIsolatedVertices && shell.empty())
                    vertexToBeRemoved.push_back(t[v]);
            }
        }

        if(m_container->hasHexahedraAroundEdge())
        {
            for(unsigned int e=0; e<12; ++e)
            {
                sofa::helper::vector< unsigned int > &shell = m_container->m_hexahedraAroundEdge[ m_container->m_edgesInHexahedron[indices[i]][e]];
                shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
                if(removeIsolatedEdges && shell.empty())
                    edgeToBeRemoved.push_back(m_container->m_edgesInHexahedron[indices[i]][e]);
            }
        }

        if(m_container->hasHexahedraAroundQuad())
        {
            for(unsigned int q=0; q<6; ++q)
            {
                sofa::helper::vector< unsigned int > &shell = m_container->m_hexahedraAroundQuad[ m_container->m_quadsInHexahedron[indices[i]][q]];
                shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
                if(removeIsolatedQuads && shell.empty())
                    quadToBeRemoved.push_back(m_container->m_quadsInHexahedron[indices[i]][q]);
            }
        }

        // now updates the shell information of the edge formely at the end of the array
        if( indices[i] < lastHexahedron )
        {
            if(m_container->hasHexahedraAroundVertex())
            {
                for(unsigned int v=0; v<8; ++v)
                {
                    sofa::helper::vector< unsigned int > &shell = m_container->m_hexahedraAroundVertex[ h[v] ];
                    replace(shell.begin(), shell.end(), lastHexahedron, indices[i]);
                }
            }

            if(m_container->hasHexahedraAroundEdge())
            {
                for(unsigned int e=0; e<12; ++e)
                {
                    sofa::helper::vector< unsigned int > &shell =  m_container->m_hexahedraAroundEdge[ m_container->m_edgesInHexahedron[lastHexahedron][e]];
                    replace(shell.begin(), shell.end(), lastHexahedron, indices[i]);
                }
            }

            if(m_container->hasHexahedraAroundQuad())
            {
                for(unsigned int q=0; q<6; ++q)
                {
                    sofa::helper::vector< unsigned int > &shell =  m_container->m_hexahedraAroundQuad[ m_container->m_quadsInHexahedron[lastHexahedron][q]];
                    replace(shell.begin(), shell.end(), lastHexahedron, indices[i]);
                }
            }
        }

        if(m_container->hasQuadsInHexahedron())
        {
            // removes the quadsInHexahedrons from the quadsInHexahedronArray
            m_container->m_quadsInHexahedron[ indices[i] ] = m_container->m_quadsInHexahedron[ lastHexahedron ]; // overwriting with last valid value.
            m_container->m_quadsInHexahedron.resize( lastHexahedron ); // resizing to erase multiple occurence of the hexa.
        }

        if(m_container->hasEdgesInHexahedron())
        {
            // removes the edgesInHexahedrons from the edgesInHexahedronArray
            m_container->m_edgesInHexahedron[ indices[i] ] = m_container->m_edgesInHexahedron[ lastHexahedron ]; // overwriting with last valid value.
            m_container->m_edgesInHexahedron.resize( lastHexahedron ); // resizing to erase multiple occurence of the hexa.
        }

        // removes the hexahedron from the hexahedronArray
        m_hexahedron[ indices[i] ] = m_hexahedron[ lastHexahedron ]; // overwriting with last valid value.
        m_hexahedron.resize( lastHexahedron ); // resizing to erase multiple occurence of the hexa.
    }

    if( (!quadToBeRemoved.empty()) || (!edgeToBeRemoved.empty()))
    {
        if(!quadToBeRemoved.empty())
        {
            /// warn that quads will be deleted
            removeQuadsWarning(quadToBeRemoved);
        }

        if(!edgeToBeRemoved.empty())
        {
            /// warn that edges will be deleted
            removeEdgesWarning(edgeToBeRemoved);
        }

        propagateTopologicalChanges();

        if(!quadToBeRemoved.empty())
        {
            /// actually remove quads without looking for isolated vertices
            removeQuadsProcess(quadToBeRemoved, false, false);
        }

        if(!edgeToBeRemoved.empty())
        {
            /// actually remove edges without looking for isolated vertices
            removeEdgesProcess(edgeToBeRemoved, false);
        }
    }

    if(!vertexToBeRemoved.empty())
    {
        removePointsWarning(vertexToBeRemoved);
        propagateTopologicalChanges();
        removePointsProcess(vertexToBeRemoved);
    }
}
void QuadSetTopologyModifier::removeQuadsProcess(const sofa::helper::vector<unsigned int> &indices,
        const bool removeIsolatedEdges,
        const bool removeIsolatedPoints)
{
    if(!m_container->hasQuads()) // this method should only be called when quads exist
    {
#ifndef NDEBUG
        sout << "Error. [QuadSetTopologyModifier::removeQuadsProcess] quad array is empty." << sendl;
#endif
        return;
    }

    if(m_container->hasEdges() && removeIsolatedEdges)
    {
        if(!m_container->hasEdgesInQuad())
            m_container->createEdgesInQuadArray();

        if(!m_container->hasQuadsAroundEdge())
            m_container->createQuadsAroundEdgeArray();
    }

    if(removeIsolatedPoints)
    {
        if(!m_container->hasQuadsAroundVertex())
            m_container->createQuadsAroundVertexArray();
    }

    sofa::helper::vector<unsigned int> edgeToBeRemoved;
    sofa::helper::vector<unsigned int> vertexToBeRemoved;
    helper::WriteAccessor< Data< sofa::helper::vector<Quad> > > m_quad = m_container->d_quad;

    unsigned int lastQuad = m_container->getNumberOfQuads() - 1;
    for(unsigned int i=0; i<indices.size(); ++i, --lastQuad)
    {
        const Quad &t = m_quad[ indices[i] ];
        const Quad &q = m_quad[ lastQuad ];

        // first check that the quad vertex shell array has been initialized
        if(m_container->hasQuadsAroundVertex())
        {
            for(unsigned int v=0; v<4; ++v)
            {
                sofa::helper::vector< unsigned int > &shell = m_container->m_quadsAroundVertex[ t[v] ];
                shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
                if(removeIsolatedPoints && shell.empty())
                    vertexToBeRemoved.push_back(t[v]);
            }
        }

        if(m_container->hasQuadsAroundEdge())
        {
            for(unsigned int e=0; e<4; ++e)
            {
                sofa::helper::vector< unsigned int > &shell = m_container->m_quadsAroundEdge[ m_container->m_edgesInQuad[indices[i]][e]];
                shell.erase(remove(shell.begin(), shell.end(), indices[i]), shell.end());
                if(removeIsolatedEdges && shell.empty())
                    edgeToBeRemoved.push_back(m_container->m_edgesInQuad[indices[i]][e]);
            }
        }

        if(indices[i] < lastQuad)
        {
            // now updates the shell information of the quad at the end of the array
            if(m_container->hasQuadsAroundVertex())
            {
                for(unsigned int v=0; v<4; ++v)
                {
                    sofa::helper::vector< unsigned int > &shell = m_container->m_quadsAroundVertex[ q[v] ];
                    replace(shell.begin(), shell.end(), lastQuad, indices[i]);
                }
            }

            if(m_container->hasQuadsAroundEdge())
            {
                for(unsigned int e=0; e<4; ++e)
                {
                    sofa::helper::vector< unsigned int > &shell =  m_container->m_quadsAroundEdge[ m_container->m_edgesInQuad[lastQuad][e]];
                    replace(shell.begin(), shell.end(), lastQuad, indices[i]);
                }
            }
        }

        // removes the edgesInQuads from the edgesInQuadsArray
        if(m_container->hasEdgesInQuad())
        {
            m_container->m_edgesInQuad[ indices[i] ] = m_container->m_edgesInQuad[ lastQuad ]; // overwriting with last valid value.
            m_container->m_edgesInQuad.resize( lastQuad ); // resizing to erase multiple occurence of the quad.
        }

        // removes the quad from the quadArray
        m_quad[ indices[i] ] = m_quad[ lastQuad ]; // overwriting with last valid value.
        m_quad.resize( lastQuad ); // resizing to erase multiple occurence of the quad.
    }

    if(!edgeToBeRemoved.empty())
    {
        /// warn that edges will be deleted
        removeEdgesWarning(edgeToBeRemoved);
        propagateTopologicalChanges();
        /// actually remove edges without looking for isolated vertices
        removeEdgesProcess(edgeToBeRemoved,false);
    }

    if(!vertexToBeRemoved.empty())
    {
        removePointsWarning(vertexToBeRemoved);
        /// propagate to all components
        propagateTopologicalChanges();
        removePointsProcess(vertexToBeRemoved);
    }
}