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