X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Cartesian_3D.cxx;h=7e444be893672c8d92438e4a8bc527f2f06ccf0d;hp=96bbf63f5df11020d8f425ac787ec319b1c34064;hb=951dd4234ec84d147b1756bc04b6464c5332091c;hpb=dfcc0eb72b126380c8da3d725f90c9ee43f59827 diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index 96bbf63f5..7e444be89 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -362,6 +362,9 @@ namespace gp_XYZ _origin; gp_Mat _invB; // inverted basis of _axes + // index shift within _nodes of nodes of a cell from the 1st node + int _nodeShift[8]; + vector< const SMDS_MeshNode* > _nodes; // mesh nodes at grid nodes vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry ObjectPool< E_IntersectPoint > _edgeIntPool; // intersections with EDGEs @@ -375,7 +378,6 @@ namespace bool _toUseThresholdForInternalFaces; double _sizeThreshold; - vector< TGeomID > _shapeIDs; // returned by Hexahedron::getSolids() SMESH_MesherHelper* _helper; size_t CellIndex( size_t i, size_t j, size_t k ) const @@ -428,6 +430,7 @@ namespace bool IsBoundaryFace( TGeomID face ) const { return _geometry._boundaryFaces.Contains( face ); } void SetOnShape( const SMDS_MeshNode* n, const F_IntersectPoint& ip, bool unset=false ); bool IsToCheckNodePos() const { return !_toAddEdges && _toCreateFaces; } + bool IsToRemoveExcessEntities() const { return !_toAddEdges; } void SetCoordinates(const vector& xCoords, const vector& yCoords, @@ -443,12 +446,14 @@ namespace */ struct CellsAroundLink { + int _iDir; int _dInd[4][3]; size_t _nbCells[3]; int _i,_j,_k; Grid* _grid; CellsAroundLink( Grid* grid, int iDir ): + _iDir( iDir ), _dInd{ {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }, _nbCells{ grid->_coords[0].size() - 1, grid->_coords[1].size() - 1, @@ -467,7 +472,7 @@ namespace _j = j - _dInd[iL][1]; _k = k - _dInd[iL][2]; } - bool GetCell( int iL, int& i, int& j, int& k, int& cellIndex ) + bool GetCell( int iL, int& i, int& j, int& k, int& cellIndex, int& linkIndex ) { i = _i + _dInd[iL][0]; j = _j + _dInd[iL][1]; @@ -477,6 +482,7 @@ namespace k < 0 || k >= (int)_nbCells[2] ) return false; cellIndex = _grid->CellIndex( i,j,k ); + linkIndex = iL + _iDir * 4; return true; } }; @@ -760,9 +766,13 @@ namespace // -------------------------------------------------------------------------------- struct _Face { + SMESH_Block::TShapeID _name; vector< _OrientedLink > _links; // links on GridLine's vector< _Link > _polyLinks; // links added to close a polygonal face vector< _Node* > _eIntNodes; // nodes at intersection with EDGEs + + _Face():_name( SMESH_Block::ID_NONE ) + {} bool IsPolyLink( const _OrientedLink& ol ) { return _polyLinks.empty() ? false : @@ -790,41 +800,79 @@ namespace // -------------------------------------------------------------------------------- struct _volumeDef // holder of nodes of a volume mesh element { + typedef void* _ptr; + struct _nodeDef { const SMDS_MeshNode* _node; // mesh node at hexahedron corner const B_IntersectPoint* _intPoint; + _nodeDef(): _node(0), _intPoint(0) {} _nodeDef( _Node* n ): _node( n->_node), _intPoint( n->_intPoint ) {} const SMDS_MeshNode* Node() const { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; } const E_IntersectPoint* EdgeIntPnt() const { return static_cast< const E_IntersectPoint* >( _intPoint ); } + _ptr Ptr() const { return Node() ? (_ptr) Node() : (_ptr) EdgeIntPnt(); } + bool operator==(const _nodeDef& other ) const { return Ptr() == other.Ptr(); } }; + vector< _nodeDef > _nodes; vector< int > _quantities; _volumeDef* _next; // to store several _volumeDefs in a chain TGeomID _solidID; const SMDS_MeshElement* _volume; // new volume + vector< SMESH_Block::TShapeID > _names; // name of side a polygon originates from + _volumeDef(): _next(0), _solidID(0), _volume(0) {} ~_volumeDef() { delete _next; } _volumeDef( _volumeDef& other ): _next(0), _solidID( other._solidID ), _volume( other._volume ) - { _nodes.swap( other._nodes ); _quantities.swap( other._quantities ); other._volume = 0; } + { _nodes.swap( other._nodes ); _quantities.swap( other._quantities ); other._volume = 0; + _names.swap( other._names ); } - void Set( const vector< _Node* >& nodes, const vector< int >& quant = vector< int >() ) - { _nodes.assign( nodes.begin(), nodes.end() ); _quantities = quant; } + size_t size() const { return 1 + ( _next ? _next->size() : 0 ); } + _volumeDef* at(int index) + { return index == 0 ? this : ( _next ? _next->at(index-1) : _next ); } void Set( _Node** nodes, int nb ) { _nodes.assign( nodes, nodes + nb ); } void SetNext( _volumeDef* vd ) { if ( _next ) { _next->SetNext( vd ); } else { _next = vd; }} + + bool IsEmpty() const { return (( _nodes.empty() ) && + ( !_next || _next->IsEmpty() )); } + bool IsPolyhedron() const { return ( !_quantities.empty() || + ( _next && !_next->_quantities.empty() )); } + + + struct _linkDef: public std::pair<_ptr,_ptr> // to join polygons in removeExcessSideDivision() + { + _nodeDef _node1;//, _node2; + mutable /*const */_linkDef *_prev, *_next; + size_t _loopIndex; + + _linkDef():_prev(0), _next(0) {} + + void init( const _nodeDef& n1, const _nodeDef& n2, size_t iLoop ) + { + _node1 = n1; //_node2 = n2; + _loopIndex = iLoop; + first = n1.Ptr(); + second = n2.Ptr(); + if ( first > second ) std::swap( first, second ); + } + void setNext( _linkDef* next ) + { + _next = next; + next->_prev = this; + } + }; }; // topology of a hexahedron - int _nodeShift[8]; _Node _hexNodes [8]; _Link _hexLinks [12]; _Face _hexQuads [6]; @@ -838,7 +886,7 @@ namespace // additional nodes created at intersection points vector< _Node > _intNodes; - // nodes inside the hexahedron (at VERTEXes) + // nodes inside the hexahedron (at VERTEXes) refer to _intNodes vector< _Node* > _vIntNodes; // computed volume elements @@ -859,7 +907,7 @@ namespace Hexahedron(Grid* grid); int MakeElements(SMESH_MesherHelper& helper, const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap); - void ComputeElements( const Solid* solid = 0, int solidIndex = -1 ); + void computeElements( const Solid* solid = 0, int solidIndex = -1 ); private: Hexahedron(const Hexahedron& other, size_t i, size_t j, size_t k, int cellID ); @@ -867,7 +915,7 @@ namespace void init( size_t i ); void setIJK( size_t i ); bool compute( const Solid* solid, const IsInternalFlag intFlag ); - const vector< TGeomID >& getSolids(); + size_t getSolids( TGeomID ids[] ); bool isCutByInternalFace( IsInternalFlag & maxFlag ); void addEdges(SMESH_MesherHelper& helper, vector< Hexahedron* >& intersectedHex, @@ -894,6 +942,8 @@ namespace const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap ); void getVolumes( vector< const SMDS_MeshElement* > & volumes ); void getBoundaryElems( vector< const SMDS_MeshElement* > & boundaryVolumes ); + void removeExcessSideDivision(const vector< Hexahedron* >& allHexa); + void removeExcessNodes(vector< Hexahedron* >& allHexa); TGeomID getAnyFace() const; void cutByExtendedInternal( std::vector< Hexahedron* >& hexes, const TColStd_MapOfInteger& intEdgeIDs ); @@ -928,7 +978,7 @@ namespace TID2Nb::iterator id2nb = id2nbMap.insert( s0 ).first; id2nb->second++; } - }; + }; // class Hexahedron #ifdef WITH_TBB // -------------------------------------------------------------------------- @@ -943,7 +993,7 @@ namespace { for ( size_t i = r.begin(); i != r.end(); ++i ) if ( Hexahedron* hex = _hexVec[ i ] ) - hex->ComputeElements(); + hex->computeElements(); } }; // -------------------------------------------------------------------------- @@ -2090,14 +2140,14 @@ namespace size_t i101 = i100 + dz; size_t i011 = i010 + dz; size_t i111 = i110 + dz; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V000 )] = i000; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V100 )] = i100; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V010 )] = i010; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V110 )] = i110; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V001 )] = i001; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V101 )] = i101; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V011 )] = i011; - _nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V111 )] = i111; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V000 )] = i000; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V100 )] = i100; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V010 )] = i010; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V110 )] = i110; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V001 )] = i001; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V101 )] = i101; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V011 )] = i011; + grid->_nodeShift[ SMESH_Block::ShapeIndex( SMESH_Block::ID_V111 )] = i111; vector< int > idVec; // set nodes to links @@ -2113,8 +2163,10 @@ namespace int interlace[4] = { 0, 3, 1, 2 }; // to walk by links around a face: { u0, 1v, u1, 0v } for ( int faceID = SMESH_Block::ID_Fxy0; faceID <= SMESH_Block::ID_F1yz; ++faceID ) { - SMESH_Block::GetFaceEdgesIDs( faceID, idVec ); _Face& quad = _hexQuads[ SMESH_Block::ShapeIndex( faceID )]; + quad._name = (SMESH_Block::TShapeID) faceID; + + SMESH_Block::GetFaceEdgesIDs( faceID, idVec ); bool revFace = ( faceID == SMESH_Block::ID_Fxy0 || faceID == SMESH_Block::ID_Fx1z || faceID == SMESH_Block::ID_F0yz ); @@ -2142,9 +2194,6 @@ namespace _polygons.reserve(100); // to avoid reallocation; // copy topology - for ( int i = 0; i < 8; ++i ) - _nodeShift[i] = other._nodeShift[i]; - for ( int i = 0; i < 12; ++i ) { const _Link& srcLink = other._hexLinks[ i ]; @@ -2157,6 +2206,7 @@ namespace { const _Face& srcQuad = other._hexQuads[ i ]; _Face& tgtQuad = this->_hexQuads[ i ]; + tgtQuad._name = srcQuad._name; tgtQuad._links.resize(4); for ( int j = 0; j < 4; ++j ) { @@ -2175,13 +2225,12 @@ namespace /*! * \brief Return IDs of SOLIDs interfering with this Hexahedron */ - const vector< TGeomID >& Hexahedron::getSolids() + size_t Hexahedron::getSolids( TGeomID ids[] ) { - _grid->_shapeIDs.clear(); if ( _grid->_geometry.IsOneSolid() ) { - _grid->_shapeIDs.push_back( _grid->GetSolid()->ID() ); - return _grid->_shapeIDs; + ids[0] = _grid->GetSolid()->ID(); + return 1; } // count intersection points belonging to each SOLID TID2Nb id2NbPoints; @@ -2190,8 +2239,8 @@ namespace _origNodeInd = _grid->NodeIndex( _i,_j,_k ); for ( int iN = 0; iN < 8; ++iN ) { - _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; - _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _grid->_nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _grid->_nodeShift[iN] ]; if ( _hexNodes[iN]._intPoint ) // intersection with a FACE { @@ -2231,12 +2280,12 @@ namespace insertAndIncrement( solidIDs[i], id2NbPoints ); } - _grid->_shapeIDs.reserve( id2NbPoints.size() ); + size_t nbSolids = 0; for ( TID2Nb::iterator id2nb = id2NbPoints.begin(); id2nb != id2NbPoints.end(); ++id2nb ) if ( id2nb->second >= 3 ) - _grid->_shapeIDs.push_back( id2nb->first ); + ids[ nbSolids++ ] = id2nb->first; - return _grid->_shapeIDs; + return nbSolids; } //================================================================================ @@ -2350,8 +2399,8 @@ namespace { _hexNodes[iN]._isInternalFlags = 0; - _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; - _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _grid->_nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _grid->_nodeShift[iN] ]; if ( _hexNodes[iN]._node && !solid->Contains( _hexNodes[iN]._node->GetShapeID() )) _hexNodes[iN]._node = 0; @@ -2571,21 +2620,22 @@ namespace /*! * \brief Compute mesh volumes resulted from intersection of the Hexahedron */ - void Hexahedron::ComputeElements( const Solid* solid, int solidIndex ) + void Hexahedron::computeElements( const Solid* solid, int solidIndex ) { if ( !solid ) { solid = _grid->GetSolid(); if ( !_grid->_geometry.IsOneSolid() ) { - const vector< TGeomID >& solidIDs = getSolids(); - if ( solidIDs.size() > 1 ) + TGeomID solidIDs[20]; + size_t nbSolids = getSolids( solidIDs ); + if ( nbSolids > 1 ) { - for ( size_t i = 0; i < solidIDs.size(); ++i ) + for ( size_t i = 0; i < nbSolids; ++i ) { solid = _grid->GetSolid( solidIDs[i] ); - ComputeElements( solid, i ); - if ( !_volumeDefs._nodes.empty() && i < solidIDs.size() - 1 ) + computeElements( solid, i ); + if ( !_volumeDefs._nodes.empty() && i < nbSolids - 1 ) _volumeDefs.SetNext( new _volumeDef( _volumeDefs )); } return; @@ -2649,6 +2699,7 @@ namespace _polygons.resize( _polygons.size() + 1 ); _Face* polygon = &_polygons.back(); polygon->_polyLinks.reserve( 20 ); + polygon->_name = quad._name; splits.clear(); for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle @@ -2683,6 +2734,7 @@ namespace _polygons.resize( _polygons.size() + 1 ); polygon = &_polygons.back(); polygon->_polyLinks.reserve( 20 ); + polygon->_name = quad._name; } polygon->_links.push_back( splits[ iS ] ); splits[ iS++ ]._link = 0; @@ -3149,6 +3201,40 @@ namespace if ( _hasTooSmall ) return false; // too small volume + + // Try to find out names of no-name polygons (issue # 19887) + if ( _grid->IsToRemoveExcessEntities() && _polygons.back()._name == SMESH_Block::ID_NONE ) + { + gp_XYZ uvwCenter = + 0.5 * ( _grid->_coords[0][_i] + _grid->_coords[0][_i+1] ) * _grid->_axes[0] + + 0.5 * ( _grid->_coords[1][_j] + _grid->_coords[1][_j+1] ) * _grid->_axes[1] + + 0.5 * ( _grid->_coords[2][_k] + _grid->_coords[2][_k+1] ) * _grid->_axes[2]; + for ( size_t i = _polygons.size() - 1; _polygons[i]._name == SMESH_Block::ID_NONE; --i ) + { + _Face& face = _polygons[ i ]; + Bnd_Box bb; + gp_Pnt uvw; + for ( size_t iL = 0; iL < face._links.size(); ++iL ) + { + _Node* n = face._links[ iL ].FirstNode(); + gp_XYZ p = SMESH_NodeXYZ( n->Node() ); + _grid->ComputeUVW( p, uvw.ChangeCoord().ChangeData() ); + bb.Add( uvw ); + } + gp_Pnt pMin = bb.CornerMin(); + if ( bb.IsXThin( _grid->_tol )) + face._name = pMin.X() < uvwCenter.X() ? SMESH_Block::ID_F0yz : SMESH_Block::ID_F1yz; + else if ( bb.IsYThin( _grid->_tol )) + face._name = pMin.Y() < uvwCenter.Y() ? SMESH_Block::ID_Fx0z : SMESH_Block::ID_Fx1z; + else if ( bb.IsZThin( _grid->_tol )) + face._name = pMin.Z() < uvwCenter.Z() ? SMESH_Block::ID_Fxy0 : SMESH_Block::ID_Fxy1; + } + } + + _volumeDefs._nodes.clear(); + _volumeDefs._quantities.clear(); + _volumeDefs._names.clear(); + // create a classic cell if possible int nbPolygons = 0; @@ -3169,14 +3255,12 @@ namespace else if ( nbNodes == 5 && nbPolygons == 5 ) isClassicElem = addPyra (); if ( !isClassicElem ) { - _volumeDefs._nodes.clear(); - _volumeDefs._quantities.clear(); - for ( size_t iF = 0; iF < _polygons.size(); ++iF ) { const size_t nbLinks = _polygons[ iF ]._links.size(); if ( nbLinks == 0 ) continue; _volumeDefs._quantities.push_back( nbLinks ); + _volumeDefs._names.push_back( _polygons[ iF ]._name ); for ( size_t iL = 0; iL < nbLinks; ++iL ) _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() ); } @@ -3200,7 +3284,7 @@ namespace int nbIntHex = 0; // set intersection nodes from GridLine's to links of allHexa - int i,j,k, cellIndex; + int i,j,k, cellIndex, iLink; for ( int iDir = 0; iDir < 3; ++iDir ) { // loop on GridLine's parallel to iDir @@ -3217,7 +3301,7 @@ namespace fourCells.Init( lineInd.I(), lineInd.J(), lineInd.K() ); for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link { - if ( !fourCells.GetCell( iL, i,j,k, cellIndex )) + if ( !fourCells.GetCell( iL, i,j,k, cellIndex, iLink )) continue; Hexahedron *& hex = allHexa[ cellIndex ]; if ( !hex) @@ -3225,7 +3309,6 @@ namespace hex = new Hexahedron( *this, i, j, k, cellIndex ); ++nbIntHex; } - const int iLink = iL + iDir * 4; hex->_hexLinks[iLink]._fIntPoints.push_back( &(*ip) ); hex->_nbFaceIntNodes += bool( ip->_node ); } @@ -3238,6 +3321,7 @@ namespace // add not split hexahedra to the mesh int nbAdded = 0; + TGeomID solidIDs[20]; vector< Hexahedron* > intHexa; intHexa.reserve( nbIntHex ); vector< const SMDS_MeshElement* > boundaryVolumes; boundaryVolumes.reserve( nbIntHex * 1.1 ); for ( size_t i = 0; i < allHexa.size(); ++i ) @@ -3273,7 +3357,8 @@ namespace } else { - solidID = getSolids()[0]; + getSolids( solidIDs ); + solidID = solidIDs[0]; } mesh->SetMeshElementOnShape( el, solidID ); ++nbAdded; @@ -3293,22 +3378,33 @@ namespace } } - // add elements resulted from hexadron intersection + // compute definitions of volumes resulted from hexadron intersection #ifdef WITH_TBB tbb::parallel_for ( tbb::blocked_range( 0, intHexa.size() ), ParallelHexahedron( intHexa ), - tbb::simple_partitioner()); // ComputeElements() is called here + tbb::simple_partitioner()); // computeElements() is called here +#else for ( size_t i = 0; i < intHexa.size(); ++i ) if ( Hexahedron * hex = intHexa[ i ] ) - nbAdded += hex->addVolumes( helper ); -#else + hex->computeElements(); +#endif + + // simplify polyhedrons + if ( _grid->IsToRemoveExcessEntities() ) + { + for ( size_t i = 0; i < intHexa.size(); ++i ) + if ( Hexahedron * hex = intHexa[ i ] ) + hex->removeExcessSideDivision( allHexa ); + + for ( size_t i = 0; i < intHexa.size(); ++i ) + if ( Hexahedron * hex = intHexa[ i ] ) + hex->removeExcessNodes( allHexa ); + } + + // add volumes for ( size_t i = 0; i < intHexa.size(); ++i ) if ( Hexahedron * hex = intHexa[ i ] ) - { - hex->ComputeElements(); nbAdded += hex->addVolumes( helper ); - } -#endif // fill boundaryVolumes with volumes neighboring too small skipped volumes if ( _grid->_toCreateFaces ) @@ -3603,7 +3699,8 @@ namespace int i = ! ( u < _grid->_tol ); // [0,1] int iN = link._nodes[ i ] - hex->_hexNodes; // [0-7] - const F_IntersectPoint * & ip = _grid->_gridIntP[ hex->_origNodeInd + _nodeShift[iN] ]; + const F_IntersectPoint * & ip = _grid->_gridIntP[ hex->_origNodeInd + + _grid->_nodeShift[iN] ]; if ( !ip ) { ip = _grid->_extIntPool.getNew(); @@ -3631,13 +3728,12 @@ namespace int i,j,k, cellIndex; for ( int iC = 0; iC < 4; ++iC ) // loop on 4 cells sharing the link { - if ( !fourCells.GetCell( iC, i,j,k, cellIndex )) + if ( !fourCells.GetCell( iC, i,j,k, cellIndex, iLink )) continue; Hexahedron * h = hexes[ cellIndex ]; if ( !h ) h = hexes[ cellIndex ] = new Hexahedron( *this, i, j, k, cellIndex ); - const int iL = iC + iDir * 4; - h->_hexLinks[iL]._fIntPoints.push_back( ip ); + h->_hexLinks[iLink]._fIntPoints.push_back( ip ); h->_nbFaceIntNodes++; //isCut = true; } @@ -3697,8 +3793,8 @@ namespace for ( size_t iN = 0; iN < 8; ++iN ) // check corners { - _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; - _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _grid->_nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _grid->_nodeShift[iN] ]; if ( _hexNodes[iN]._intPoint ) for ( size_t iF = 0; iF < _hexNodes[iN]._intPoint->_faceIDs.size(); ++iF ) { @@ -4957,7 +5053,7 @@ namespace /*! * \brief Return created volumes and volumes that can have free facet because of * skipped small volume. Also create mesh faces on free facets - * of adjacent not-cut volumes id the result volume is too small. + * of adjacent not-cut volumes if the result volume is too small. */ void Hexahedron::getBoundaryElems( vector< const SMDS_MeshElement* > & boundaryElems ) { @@ -5004,8 +5100,9 @@ namespace if ( !faceID ) break; if ( _grid->IsInternal( faceID ) || - _grid->IsShared( faceID ) || - _grid->IsBoundaryFace( faceID )) + _grid->IsShared( faceID ) //|| + //_grid->IsBoundaryFace( faceID ) -- commented for #19887 + ) break; // create only if a new face will be used by other 3D algo } @@ -5034,6 +5131,337 @@ namespace } } + //================================================================================ + /*! + * \brief Remove edges and nodes dividing a hexa side in the case if an adjacent + * volume also sharing the dividing edge is missing due to its small side. + * Issue #19887. + */ + //================================================================================ + + void Hexahedron::removeExcessSideDivision(const vector< Hexahedron* >& allHexa) + { + if ( ! _volumeDefs.IsPolyhedron() ) + return; // not a polyhedron + + // look for a divided side adjacent to a small hexahedron + + int di[6] = { 0, 0, 0, 0,-1, 1 }; + int dj[6] = { 0, 0,-1, 1, 0, 0 }; + int dk[6] = {-1, 1, 0, 0, 0, 0 }; + + for ( int iF = 0; iF < 6; ++iF ) // loop on 6 sides of a hexahedron + { + size_t neighborIndex = _grid->CellIndex( _i + di[iF], + _j + dj[iF], + _k + dk[iF] ); + if ( neighborIndex >= allHexa.size() || + !allHexa[ neighborIndex ] || + !allHexa[ neighborIndex ]->_hasTooSmall ) + continue; + + // check if a side is divided into several polygons + for ( _volumeDef* volDef = &_volumeDefs; volDef; volDef = volDef->_next ) + { + int nbPolygons = 0, nbNodes = 0; + for ( size_t i = 0; i < volDef->_names.size(); ++i ) + if ( volDef->_names[ i ] == _hexQuads[ iF ]._name ) + { + ++nbPolygons; + nbNodes += volDef->_quantities[ i ]; + } + if ( nbPolygons < 2 ) + continue; + + // construct loops from polygons + typedef _volumeDef::_linkDef TLinkDef; + std::vector< TLinkDef* > loops; + std::vector< TLinkDef > links( nbNodes ); + for ( size_t i = 0, iN = 0, iLoop = 0; iLoop < volDef->_quantities.size(); ++iLoop ) + { + size_t nbLinks = volDef->_quantities[ iLoop ]; + if ( volDef->_names[ iLoop ] != _hexQuads[ iF ]._name ) + { + iN += nbLinks; + continue; + } + loops.push_back( & links[i] ); + for ( size_t n = 0; n < nbLinks-1; ++n, ++i, ++iN ) + { + links[i].init( volDef->_nodes[iN], volDef->_nodes[iN+1], iLoop ); + links[i].setNext( &links[i+1] ); + } + links[i].init( volDef->_nodes[iN], volDef->_nodes[iN-nbLinks+1], iLoop ); + links[i].setNext( &links[i-nbLinks+1] ); + ++i; ++iN; + } + + // look for equal links in different loops and join such loops + bool loopsJoined = false; + std::set< TLinkDef > linkSet; + for ( size_t iLoop = 0; iLoop < loops.size(); ++iLoop ) + { + TLinkDef* beg = 0; + for ( TLinkDef* l = loops[ iLoop ]; l != beg; l = l->_next ) // walk around the iLoop + { + std::pair< std::set< TLinkDef >::iterator, bool > it2new = linkSet.insert( *l ); + if ( !it2new.second ) // equal found, join loops + { + const TLinkDef* equal = &(*it2new.first); + if ( equal->_loopIndex == l->_loopIndex ) + continue; // error? + + loopsJoined = true; + + for ( size_t i = iLoop - 1; i < loops.size(); --i ) + if ( loops[ i ] && loops[ i ]->_loopIndex == equal->_loopIndex ) + loops[ i ] = 0; + + // exclude l and equal and join two loops + if ( l->_prev != equal ) + l->_prev->setNext( equal->_next ); + if ( equal->_prev != l ) + equal->_prev->setNext( l->_next ); + + if ( volDef->_quantities[ l->_loopIndex ] > 0 ) + volDef->_quantities[ l->_loopIndex ] *= -1; + if ( volDef->_quantities[ equal->_loopIndex ] > 0 ) + volDef->_quantities[ equal->_loopIndex ] *= -1; + + if ( loops[ iLoop ] == l ) + loops[ iLoop ] = l->_prev->_next; + } + beg = loops[ iLoop ]; + } + } + // update volDef + if ( loopsJoined ) + { + // set unchanged polygons + std::vector< int > newQuantities; + std::vector< _volumeDef::_nodeDef > newNodes; + vector< SMESH_Block::TShapeID > newNames; + newQuantities.reserve( volDef->_quantities.size() ); + newNodes.reserve ( volDef->_nodes.size() ); + newNames.reserve ( volDef->_names.size() ); + for ( size_t i = 0, iLoop = 0; iLoop < volDef->_quantities.size(); ++iLoop ) + { + if ( volDef->_quantities[ iLoop ] < 0 ) + { + i -= volDef->_quantities[ iLoop ]; + continue; + } + newQuantities.push_back( volDef->_quantities[ iLoop ]); + newNodes.insert( newNodes.end(), + volDef->_nodes.begin() + i, + volDef->_nodes.begin() + i + newQuantities.back() ); + newNames.push_back( volDef->_names[ iLoop ]); + i += volDef->_quantities[ iLoop ]; + } + + // set joined loops + for ( size_t iLoop = 0; iLoop < loops.size(); ++iLoop ) + { + if ( !loops[ iLoop ] ) + continue; + newQuantities.push_back( 0 ); + TLinkDef* beg = 0; + for ( TLinkDef* l = loops[ iLoop ]; l != beg; l = l->_next, ++newQuantities.back() ) + { + newNodes.push_back( l->_node1 ); + beg = loops[ iLoop ]; + } + newNames.push_back( _hexQuads[ iF ]._name ); + } + volDef->_quantities.swap( newQuantities ); + volDef->_nodes.swap( newNodes ); + volDef->_names.swap( newNames ); + } + } // loop on volDef's + } // loop on hex sides + + return; + } // removeExcessSideDivision() + + + //================================================================================ + /*! + * \brief Remove nodes splitting Cartesian cell edges in the case if a node + * is used in every cells only by two polygons sharing the edge + * Issue #19887. + */ + //================================================================================ + + void Hexahedron::removeExcessNodes(vector< Hexahedron* >& allHexa) + { + if ( ! _volumeDefs.IsPolyhedron() ) + return; // not a polyhedron + + typedef vector< _volumeDef::_nodeDef >::iterator TNodeIt; + vector< int > nodesInPoly[ 4 ]; // node index in _volumeDefs._nodes + vector< int > volDefInd [ 4 ]; // index of a _volumeDefs + Hexahedron* hexa [ 4 ]; + int i,j,k, cellIndex, iLink = 0, iCellLink; + for ( int iDir = 0; iDir < 3; ++iDir ) + { + CellsAroundLink fourCells( _grid, iDir ); + for ( int iL = 0; iL < 4; ++iL, ++iLink ) // 4 links in a direction + { + _Link& link = _hexLinks[ iLink ]; + fourCells.Init( _i, _j, _k, iLink ); + + for ( size_t iP = 0; iP < link._fIntPoints.size(); ++iP ) // loop on nodes on the link + { + bool nodeRemoved = true; + _volumeDef::_nodeDef node; node._intPoint = link._fIntPoints[iP]; + + for ( size_t i = 0, nb = _volumeDefs.size(); i < nb && nodeRemoved; ++i ) + if ( _volumeDef* vol = _volumeDefs.at( i )) + nodeRemoved = + ( std::find( vol->_nodes.begin(), vol->_nodes.end(), node ) == vol->_nodes.end() ); + if ( nodeRemoved ) + continue; // node already removed + + // check if a node encounters zero or two times in 4 cells sharing iLink + // if so, the node can be removed from the cells + bool nodeIsOnEdge = true; + int nbPolyhedraWithNode = 0; + for ( int iC = 0; iC < 4; ++iC ) // loop on 4 cells sharing a link + { + nodesInPoly[ iC ].clear(); + volDefInd [ iC ].clear(); + hexa [ iC ] = 0; + if ( !fourCells.GetCell( iC, i,j,k, cellIndex, iCellLink )) + continue; + hexa[ iC ] = allHexa[ cellIndex ]; + if ( !hexa[ iC ]) + continue; + for ( size_t i = 0, nb = hexa[ iC ]->_volumeDefs.size(); i < nb; ++i ) + if ( _volumeDef* vol = hexa[ iC ]->_volumeDefs.at( i )) + { + for ( TNodeIt nIt = vol->_nodes.begin(); nIt != vol->_nodes.end(); ++nIt ) + { + nIt = std::find( nIt, vol->_nodes.end(), node ); + if ( nIt != vol->_nodes.end() ) + { + nodesInPoly[ iC ].push_back( std::distance( vol->_nodes.begin(), nIt )); + volDefInd [ iC ].push_back( i ); + } + else + break; + } + nbPolyhedraWithNode += ( !nodesInPoly[ iC ].empty() ); + } + if ( nodesInPoly[ iC ].size() != 0 && + nodesInPoly[ iC ].size() != 2 ) + { + nodeIsOnEdge = false; + break; + } + } // loop on 4 cells + + // remove nodes from polyhedra + if ( nbPolyhedraWithNode > 0 && nodeIsOnEdge ) + { + for ( int iC = 0; iC < 4; ++iC ) // loop on 4 cells sharing the link + { + if ( nodesInPoly[ iC ].empty() ) + continue; + for ( int i = volDefInd[ iC ].size() - 1; i >= 0; --i ) + { + _volumeDef* vol = hexa[ iC ]->_volumeDefs.at( volDefInd[ iC ][ i ]); + int nIndex = nodesInPoly[ iC ][ i ]; + // decrement _quantities + for ( size_t iQ = 0; iQ < vol->_quantities.size(); ++iQ ) + if ( nIndex < vol->_quantities[ iQ ]) + { + vol->_quantities[ iQ ]--; + break; + } + else + { + nIndex -= vol->_quantities[ iQ ]; + } + vol->_nodes.erase( vol->_nodes.begin() + nodesInPoly[ iC ][ i ]); + + if ( i == 0 && + vol->_nodes.size() == 6 * 4 && + vol->_quantities.size() == 6 ) // polyhedron becomes hexahedron? + { + bool allQuads = true; + for ( size_t iQ = 0; iQ < vol->_quantities.size() && allQuads; ++iQ ) + allQuads = ( vol->_quantities[ iQ ] == 4 ); + if ( allQuads ) + { + // set side nodes as this: bottom, top, top, ... + int iTop, iBot; // side indices + for ( int iS = 0; iS < 6; ++iS ) + { + if ( vol->_names[ iS ] == SMESH_Block::ID_Fxy0 ) + iBot = iS; + if ( vol->_names[ iS ] == SMESH_Block::ID_Fxy1 ) + iTop = iS; + } + if ( iBot != 0 ) + { + if ( iTop == 0 ) + { + std::copy( vol->_nodes.begin(), + vol->_nodes.begin() + 4, + vol->_nodes.begin() + 4 ); + iTop = 1; + } + std::copy( vol->_nodes.begin() + 4 * iBot, + vol->_nodes.begin() + 4 * ( iBot + 1), + vol->_nodes.begin() ); + } + if ( iTop != 1 ) + std::copy( vol->_nodes.begin() + 4 * iTop, + vol->_nodes.begin() + 4 * ( iTop + 1), + vol->_nodes.begin() + 4 ); + + std::copy( vol->_nodes.begin() + 4, + vol->_nodes.begin() + 8, + vol->_nodes.begin() + 8 ); + // set up top facet nodes by comparing their uvw with bottom nodes + E_IntersectPoint ip[8]; + for ( int iN = 0; iN < 8; ++iN ) + { + SMESH_NodeXYZ p = vol->_nodes[ iN ].Node(); + _grid->ComputeUVW( p, ip[ iN ]._uvw ); + } + const double tol2 = _grid->_tol * _grid->_tol; + for ( int iN = 0; iN < 4; ++iN ) + { + gp_Pnt2d pBot( ip[ iN ]._uvw[0], ip[ iN ]._uvw[1] ); + for ( int iT = 4; iT < 8; ++iT ) + { + gp_Pnt2d pTop( ip[ iT ]._uvw[0], ip[ iT ]._uvw[1] ); + if ( pBot.SquareDistance( pTop ) < tol2 ) + { + // vol->_nodes[ iN + 4 ]._node = ip[ iT ]._node; + // vol->_nodes[ iN + 4 ]._intPoint = 0; + vol->_nodes[ iN + 4 ] = vol->_nodes[ iT + 4 ]; + break; + } + } + } + vol->_nodes.resize( 8 ); + vol->_quantities.clear(); + //vol->_names.clear(); + } + } + } // loop on _volumeDefs + } // loop on 4 cell abound a link + } // if ( nodeIsOnEdge ) + } // loop on intersection points of a link + } // loop on 4 links of a direction + } // loop on 3 directions + + return; + + } // removeExcessNodes() + //================================================================================ /*! * \brief Set to _hexLinks a next portion of splits located on one side of INTERNAL FACEs