// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : SMESH_ProxyMesh.cxx // Created : Thu Dec 2 12:32:53 2010 // Author : Edward AGAPOV (eap) #include "SMESH_ProxyMesh.hxx" #include "SMDS_IteratorOnIterators.hxx" #include "SMDS_SetIterator.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include #include #include #include #include //================================================================================ /*! * \brief Constructor; mesh must be set by a descendant class */ //================================================================================ SMESH_ProxyMesh::SMESH_ProxyMesh():_mesh(0), _subContainer(0) { } //================================================================================ /*! * \brief Constructor */ //================================================================================ SMESH_ProxyMesh::SMESH_ProxyMesh(const SMESH_Mesh& mesh) : _mesh( &mesh ), _subContainer( new SubMesh( GetMeshDS() ) ) { } //================================================================================ /*! * \brief Make a proxy mesh from components. Components become empty */ //================================================================================ SMESH_ProxyMesh::SMESH_ProxyMesh(std::vector& components): _mesh(0) { if ( components.empty() ) return; for ( unsigned i = 0; i < components.size(); ++i ) { SMESH_ProxyMesh* m = components[i].get(); if ( !m ) continue; takeTmpElemsInMesh( m ); if ( !_mesh && m->_mesh ) setMesh( *( m->_mesh )); if ( _allowedTypes.empty() ) _allowedTypes = m->_allowedTypes; if ( _subMeshes.size() < m->_subMeshes.size() ) _subMeshes.resize( m->_subMeshes.size(), 0 ); for ( unsigned j = 0; j < m->_subMeshes.size(); ++j ) { if ( !m->_subMeshes[j] ) continue; if ( _subMeshes[j] ) { // unite 2 sub-meshes std::set< const SMDS_MeshElement * > elems( _subMeshes[j]->_elements.begin(), _subMeshes[j]->_elements.end()); elems.insert( m->_subMeshes[j]->_elements.begin(), m->_subMeshes[j]->_elements.end()); _subMeshes[j]->_elements.assign( elems.begin(), elems.end() ); m->_subMeshes[j]->_elements.clear(); if ( !_subMeshes[j]->_n2n ) _subMeshes[j]->_n2n = m->_subMeshes[j]->_n2n, m->_subMeshes[j]->_n2n = 0; else if ( _subMeshes[j]->_n2n && m->_subMeshes[j]->_n2n ) _subMeshes[j]->_n2n->insert( m->_subMeshes[j]->_n2n->begin(), m->_subMeshes[j]->_n2n->end()); } else { _subMeshes[j] = m->_subMeshes[j]; m->_subMeshes[j] = 0; } } } } //================================================================================ /*! * \brief Destructor deletes proxy submeshes and tmp elements */ //================================================================================ SMESH_ProxyMesh::~SMESH_ProxyMesh() { delete _subContainer; for ( size_t i = 0; i < _subMeshes.size(); ++i ) delete _subMeshes[i]; _subMeshes.clear(); std::set< const SMDS_MeshElement* >::iterator i = _elemsInMesh.begin(); for ( ; i != _elemsInMesh.end(); ++i ) GetMeshDS()->RemoveFreeElement( *i, 0 ); _elemsInMesh.clear(); } //================================================================================ /*! * \brief Set mesh */ //================================================================================ void SMESH_ProxyMesh::setMesh(const SMESH_Mesh& mesh) { _mesh = &mesh; if ( _mesh ) _subContainer = new SubMesh( GetMeshDS() ); } //================================================================================ /*! * \brief Returns index of a shape */ //================================================================================ int SMESH_ProxyMesh::shapeIndex(const TopoDS_Shape& shape) const { return ( shape.IsNull() || !_mesh->HasShapeToMesh() ? 0 : GetMeshDS()->ShapeToIndex(shape)); } //================================================================================ /*! * \brief Create a SubMesh * \param [ino] index - shape index * \return SubMesh* - new SubMesh */ //================================================================================ SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::newSubmesh(int index) const { return new SubMesh( GetMeshDS(),index ); } //================================================================================ /*! * \brief Returns the submesh of a shape; it can be a proxy sub-mesh */ //================================================================================ const SMESHDS_SubMesh* SMESH_ProxyMesh::GetSubMesh(const TopoDS_Shape& shape) const { return GetSubMesh( shapeIndex( shape )); } //================================================================================ /*! * \brief Return a sub-mesh by a shape ID; it can be a proxy sub-mesh */ //================================================================================ const SMESHDS_SubMesh* SMESH_ProxyMesh::GetSubMesh(const int shapeID) const { const SMESHDS_SubMesh* sm = 0; if ( 0 < shapeID && shapeID < (int)_subMeshes.size() ) sm = _subMeshes[ shapeID ]; if ( !sm ) sm = GetMeshDS()->MeshElements( shapeID ); return sm; } //================================================================================ /*! * \brief Returns the proxy sub-mesh of a shape; it can be NULL */ //================================================================================ const SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::GetProxySubMesh(const TopoDS_Shape& shape) const { size_t i = shapeIndex(shape); return i < _subMeshes.size() ? _subMeshes[i] : 0; } //================================================================================ /*! * \brief Returns the proxy node of a node; the input node is returned if no proxy exists */ //================================================================================ const SMDS_MeshNode* SMESH_ProxyMesh::GetProxyNode( const SMDS_MeshNode* node ) const { const SMDS_MeshNode* proxy = node; if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { if ( const SubMesh* proxySM = findProxySubMesh( node->getshapeId() )) proxy = proxySM->GetProxyNode( node ); } else { TopoDS_Shape shape = SMESH_MesherHelper::GetSubShapeByNode( node, GetMeshDS()); TopTools_ListIteratorOfListOfShape ancIt; if ( !shape.IsNull() ) ancIt.Initialize( _mesh->GetAncestors( shape )); for ( ; ancIt.More() && proxy == node; ancIt.Next() ) if ( const SubMesh* proxySM = findProxySubMesh( shapeIndex(ancIt.Value()))) proxy = proxySM->GetProxyNode( node ); } return proxy; } //================================================================================ /*! * \brief Returns number of proxy sub-meshes */ //================================================================================ int SMESH_ProxyMesh::NbProxySubMeshes() const { int nb = 0; for ( size_t i = 0; i < _subMeshes.size(); ++i ) nb += bool( _subMeshes[i] ); return nb; } namespace { //================================================================================ /*! * \brief Iterator filtering elements by type */ //================================================================================ class TFilteringIterator : public SMDS_ElemIterator { SMDS_ElemIteratorPtr _iter; const SMDS_MeshElement * _curElem; std::vector< SMDSAbs_EntityType> _okTypes; public: TFilteringIterator( const std::vector< SMDSAbs_EntityType>& okTypes, const SMDS_ElemIteratorPtr& elemIterator) :_iter(elemIterator), _curElem(0), _okTypes(okTypes) { next(); } virtual bool more() { return _curElem; } virtual const SMDS_MeshElement* next() { const SMDS_MeshElement* res = _curElem; _curElem = 0; while ( _iter->more() && !_curElem ) { _curElem = _iter->next(); if ( find( _okTypes.begin(), _okTypes.end(), _curElem->GetEntityType()) == _okTypes.end()) _curElem = 0; } return res; } }; //================================================================================ /*! * \brief Iterator returning unique elements from a vector and another iterator */ //================================================================================ class TUniqueIterator : public SMDS_ElemIterator { typedef boost::container::flat_set< const SMDS_MeshElement* > TElemSet; typedef SMDS_SetIterator< const SMDS_MeshElement*, TElemSet::const_iterator > TSetIterator; TElemSet _uniqueElems; TSetIterator* _iterator; public: TUniqueIterator( const std::vector< const SMDS_MeshElement* >& elems, const SMDS_ElemIteratorPtr& elemIterator ) : _uniqueElems( elems.begin(), elems.end() ) { if ( elemIterator ) while ( elemIterator->more() ) _uniqueElems.insert( elemIterator->next() ); _iterator = new TSetIterator( _uniqueElems.begin(), _uniqueElems.end() ); } ~TUniqueIterator() { delete _iterator; } virtual bool more() { return _iterator->more(); } virtual const SMDS_MeshElement* next() { return _iterator->next(); } }; //================================================================================ /*! * \brief Return iterator on 2 element iterators */ //================================================================================ SMDS_ElemIteratorPtr iteratorOn2Iterators( SMDS_ElemIteratorPtr it1, SMDS_ElemIteratorPtr it2 ) { std::vector< SMDS_ElemIteratorPtr > iters; iters.reserve(2); if ( it1 ) iters.push_back( it1 ); if ( it2 ) iters.push_back( it2 ); typedef std::vector< SMDS_ElemIteratorPtr > TElemIterVector; typedef SMDS_IteratorOnIterators TItersIter; return SMDS_ElemIteratorPtr( new TItersIter( iters )); } } //================================================================================ /*! * \brief Returns iterator on all faces on the shape taking into account substitutions */ //================================================================================ SMDS_ElemIteratorPtr SMESH_ProxyMesh::GetFaces(const TopoDS_Shape& shape) const { if ( !_mesh->HasShapeToMesh() ) return SMDS_ElemIteratorPtr(); _subContainer->RemoveAllSubmeshes(); TopTools_IndexedMapOfShape FF; TopExp::MapShapes( shape, TopAbs_FACE, FF ); for ( int i = 1; i <= FF.Extent(); ++i ) if ( const SMESHDS_SubMesh* sm = GetSubMesh( FF(i))) _subContainer->AddSubMesh( sm ); return _subContainer->SMESHDS_SubMesh::GetElements(); } //================================================================================ /*! * \brief Returns iterator on all faces of the mesh taking into account substitutions * To be used in case of mesh without shape */ //================================================================================ SMDS_ElemIteratorPtr SMESH_ProxyMesh::GetFaces() const { if ( _mesh->HasShapeToMesh() ) return SMDS_ElemIteratorPtr(); _subContainer->RemoveAllSubmeshes(); for ( unsigned i = 0; i < _subMeshes.size(); ++i ) if ( _subMeshes[i] ) _subContainer->AddSubMesh( _subMeshes[i] ); if ( _subContainer->NbSubMeshes() == 0 ) // no elements substituted return GetMeshDS()->elementsIterator(SMDSAbs_Face); // if _allowedTypes is empty, only elements from _subMeshes are returned,... SMDS_ElemIteratorPtr proxyIter = _subContainer->SMESHDS_SubMesh::GetElements(); if ( _allowedTypes.empty() || NbFaces() == _mesh->NbFaces() ) return proxyIter; // ... else elements filtered using allowedTypes are additionally returned SMDS_ElemIteratorPtr facesIter = GetMeshDS()->elementsIterator(SMDSAbs_Face); SMDS_ElemIteratorPtr filterIter( new TFilteringIterator( _allowedTypes, facesIter )); return iteratorOn2Iterators( proxyIter, filterIter ); } //================================================================================ /*! * \brief Return total nb of faces taking into account substitutions */ //================================================================================ int SMESH_ProxyMesh::NbFaces() const { int nb = 0; if ( _mesh->HasShapeToMesh() ) { TopTools_IndexedMapOfShape FF; TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_FACE, FF ); for ( int i = 1; i <= FF.Extent(); ++i ) if ( const SMESHDS_SubMesh* sm = GetSubMesh( FF(i))) nb += sm->NbElements(); } else { if ( _subMeshes.empty() ) return GetMeshDS()->NbFaces(); for ( unsigned i = 0; i < _subMeshes.size(); ++i ) if ( _subMeshes[i] ) nb += _subMeshes[i]->NbElements(); // if _allowedTypes is empty, only elements from _subMeshes are returned, // else elements filtered using allowedTypes are additionally returned if ( !_allowedTypes.empty() ) { for ( int t = SMDSEntity_Triangle; t <= SMDSEntity_Quad_Quadrangle; ++t ) { bool allowed = ( find( _allowedTypes.begin(), _allowedTypes.end(), t ) != _allowedTypes.end() ); if ( allowed ) nb += GetMeshDS()->GetMeshInfo().NbEntities( SMDSAbs_EntityType( t )); } } } return nb; } //================================================================================ /*! * \brief Returns a proxy sub-mesh; it is created if not yet exists */ //================================================================================ SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::getProxySubMesh(int index) { if ( int(_subMeshes.size()) <= index ) _subMeshes.resize( index+1, 0 ); if ( !_subMeshes[index] ) _subMeshes[index] = newSubmesh( index ); return _subMeshes[index]; } //================================================================================ /*! * \brief Returns a proxy sub-mesh; it is created if not yet exists */ //================================================================================ SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::getProxySubMesh(const TopoDS_Shape& shape) { return getProxySubMesh( shapeIndex( shape )); } //================================================================================ /*! * \brief Returns a proxy sub-mesh */ //================================================================================ SMESH_ProxyMesh::SubMesh* SMESH_ProxyMesh::findProxySubMesh(int shapeIndex) const { return shapeIndex < int(_subMeshes.size()) ? _subMeshes[shapeIndex] : 0; } //================================================================================ /*! * \brief Returns mesh DS */ //================================================================================ SMESHDS_Mesh* SMESH_ProxyMesh::GetMeshDS() const { return (SMESHDS_Mesh*)( _mesh ? _mesh->GetMeshDS() : 0 ); } //================================================================================ /*! * \brief Move proxy sub-mesh from other proxy mesh to this, returns true if sub-mesh found */ //================================================================================ bool SMESH_ProxyMesh::takeProxySubMesh( const TopoDS_Shape& shape, SMESH_ProxyMesh* proxyMesh ) { if ( proxyMesh && proxyMesh->_mesh == _mesh ) { int iS = shapeIndex( shape ); if ( SubMesh* sm = proxyMesh->findProxySubMesh( iS )) { if ( iS >= int(_subMeshes.size()) ) _subMeshes.resize( iS + 1, 0 ); _subMeshes[iS] = sm; proxyMesh->_subMeshes[iS] = 0; return true; } } return false; } //================================================================================ /*! * \brief Move tmp elements residing the _mesh from other proxy mesh to this */ //================================================================================ void SMESH_ProxyMesh::takeTmpElemsInMesh( SMESH_ProxyMesh* proxyMesh ) { if ( proxyMesh ) { _elemsInMesh.insert( proxyMesh->_elemsInMesh.begin(), proxyMesh->_elemsInMesh.end()); proxyMesh->_elemsInMesh.clear(); } } //================================================================================ /*! * \brief Removes tmp elements from the _mesh */ //================================================================================ void SMESH_ProxyMesh::removeTmpElement( const SMDS_MeshElement* elem ) { if ( elem && elem->GetID() > 0 ) { std::set< const SMDS_MeshElement* >::iterator i = _elemsInMesh.find( elem ); if ( i != _elemsInMesh.end() ) { std::vector< const SMDS_MeshNode* > nodes( elem->begin_nodes(), elem->end_nodes() ); GetMeshDS()->RemoveFreeElement( elem, 0 ); _elemsInMesh.erase( i ); for ( size_t i = 0; i < nodes.size(); ++i ) if ( nodes[i]->GetID() > 0 && nodes[i]->NbInverseElements() == 0 ) GetMeshDS()->RemoveFreeNode( nodes[i], 0, false ); } } else { delete elem; } } //================================================================================ /*! * \brief Stores tmp element residing the _mesh */ //================================================================================ void SMESH_ProxyMesh::storeTmpElement( const SMDS_MeshElement* elem ) { _elemsInMesh.insert( elem ); } //================================================================================ /*! * \brief Set node-node correspondence */ //================================================================================ void SMESH_ProxyMesh::setNode2Node(const SMDS_MeshNode* srcNode, const SMDS_MeshNode* proxyNode, const SubMesh* subMesh) { SubMesh* sm = const_cast( subMesh ); if ( !subMesh->_n2n ) sm->_n2n = new TN2NMap; sm->_n2n->insert( std::make_pair( srcNode, proxyNode )); } //================================================================================ /*! * \brief Return true if the element is a temporary one */ //================================================================================ bool SMESH_ProxyMesh::IsTemporary(const SMDS_MeshElement* elem ) const { return ( elem->GetID() < 1 ) || _elemsInMesh.count( elem ); } //================================================================================ /*! * \brief Return iterator on inverse elements of a node that may be a proxy one */ //================================================================================ SMDS_ElemIteratorPtr SMESH_ProxyMesh::GetInverseElementIterator(const SMDS_MeshNode* node, SMDSAbs_ElementType type) const { typedef std::vector< const SMDS_MeshElement* > TElemVec; TElemVec *elemVecPtr; TNodeElemVecMap& inverseElements = const_cast< TNodeElemVecMap& >( _inverseElements ); if ( inverseElements.IsEmpty() && NbProxySubMeshes() > 0 ) { TElemVec elemVec; for ( size_t i = 0; i < _subMeshes.size(); ++i ) if ( _subMeshes[i] ) for ( size_t j = 0; j < _subMeshes[i]->_elements.size(); ++j ) { const SMDS_MeshElement* e = _subMeshes[i]->_elements[j]; for ( SMDS_NodeIteratorPtr nIt = e->nodeIterator(); nIt->more(); ) { const SMDS_MeshNode* n = nIt->next(); elemVecPtr = inverseElements.ChangeSeek( n ); if ( !elemVecPtr ) elemVecPtr = inverseElements.Bound( n, elemVec ); elemVecPtr->push_back( e ); } } } SMDS_ElemIteratorPtr iter = node->GetInverseElementIterator( type ); if (( elemVecPtr = inverseElements.ChangeSeek( node ))) { if ( iter->more() ) iter = boost::make_shared< TUniqueIterator >( *elemVecPtr, iter ); else iter = boost::make_shared< SMDS_ElementVectorIterator> ( elemVecPtr->begin(), elemVecPtr->end() ); } return iter; } //================================================================================ /*! * \brief Check if a FACE has prisms on its both sides * \param [in] smFace - sub-mesh of the FACE. NOT a proxy sub-mesh! * \return bool - true if there are prisms on the two sides */ //================================================================================ bool SMESH_ProxyMesh::HasPrismsOnTwoSides( SMESHDS_SubMesh* smFace ) { if ( !smFace || smFace->NbElements() == 0 ) return false; SMDS_ElemIteratorPtr faces = smFace->GetElements(); while ( faces->more() ) { const SMDS_MeshElement* f = faces->next(); std::vector fNodes( f->begin_nodes(), f->end_nodes() ); std::vector vols; if ( SMDS_Mesh::GetElementsByNodes( fNodes, vols, SMDSAbs_Volume ) < 2 ) return false; return ( vols[0]->NbCornerNodes() == 2 * f->NbCornerNodes() && vols[1]->NbCornerNodes() == 2 * f->NbCornerNodes() ); } return false; } //================================================================================ /*! * \brief SubMesh Constructor */ //================================================================================ SMESH_ProxyMesh::SubMesh::SubMesh( const SMDS_Mesh* mesh, int index ) : SMESHDS_SubMesh( static_cast( mesh ), index ), _n2n(0) { } //================================================================================ /*! * \brief Return a proxy node or an input node */ //================================================================================ const SMDS_MeshNode* SMESH_ProxyMesh::SubMesh::GetProxyNode( const SMDS_MeshNode* n ) const { TN2NMap::iterator n2n; if ( _n2n && ( n2n = _n2n->find( n )) != _n2n->end()) return n2n->second; return n; } //================================================================================ /*! * \brief Deletes temporary elements */ //================================================================================ void SMESH_ProxyMesh::SubMesh::Clear() { for ( unsigned i = 0; i < _elements.size(); ++i ) if ( _elements[i]->GetID() < 0 ) delete _elements[i]; _elements.clear(); if ( _n2n ) delete _n2n, _n2n = 0; } //================================================================================ /*! * \brief Return number of elements in a proxy sub-mesh. The method is meaningful * for a sub-mesh containing tmp faces. */ //================================================================================ int SMESH_ProxyMesh::SubMesh::NbElements() const { return _uvPtStructVec.empty() ? _elements.size() : _uvPtStructVec.size() - 1; } //================================================================================ /*! * \brief Return elements of a proxy sub-mesh. The method is meaningful * for a sub-mesh containing tmp faces. */ //================================================================================ SMDS_ElemIteratorPtr SMESH_ProxyMesh::SubMesh::GetElements() const { return SMDS_ElemIteratorPtr ( new SMDS_ElementVectorIterator( _elements.begin(), _elements.end() )); } //================================================================================ /*! * \brief Return number of nodes in a proxy sub-mesh. The method is meaningful * for a sub-mesh containing nodes of 2D viscous layer. */ //================================================================================ int SMESH_ProxyMesh::SubMesh::NbNodes() const { return _uvPtStructVec.size(); } //================================================================================ /*! * \brief Return nodes of a proxy sub-mesh. The method is meaningful * for a sub-mesh containing nodes of 2D viscous layer. */ //================================================================================ SMDS_NodeIteratorPtr SMESH_ProxyMesh::SubMesh::GetNodes() const { if ( !_uvPtStructVec.empty() ) return SMDS_NodeIteratorPtr ( new SMDS_SetIterator < SMDS_pNode, UVPtStructVec::const_iterator, UVPtStruct::NodeAccessor > ( _uvPtStructVec.begin(), _uvPtStructVec.end() )); return SMDS_NodeIteratorPtr ( new SMDS_SetIterator< SMDS_pNode, std::vector< SMDS_pElement >::const_iterator> ( _elements.begin(), _elements.end() )); } //================================================================================ /*! * \brief Store an element */ //================================================================================ void SMESH_ProxyMesh::SubMesh::AddElement(const SMDS_MeshElement * e) { _elements.push_back( e ); } //================================================================================ /*! * \brief Check presence of element inside it-self */ //================================================================================ bool SMESH_ProxyMesh::SubMesh::Contains(const SMDS_MeshElement * ME) const { if ( ME->GetType() != SMDSAbs_Node ) return find( _elements.begin(), _elements.end(), ME ) != _elements.end(); return false; }