X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Prism_3D.cxx;h=e6db9e5014f8fe75ce40c6642fbbe689733d409b;hp=15708c450aa578097c3a528127391d1873d980a5;hb=c835e6ad6d8c2567bc40bdf242bf2110c1fe8648;hpb=385d4cede5f752d0eec26c306f3b5e14511e2a3d diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 15708c450..e6db9e501 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_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 @@ -89,20 +89,48 @@ enum { ID_BOT_FACE = SMESH_Block::ID_Fxy0, BOTTOM_EDGE = 0, TOP_EDGE, V0_EDGE, V1_EDGE, // edge IDs in face NB_WALL_FACES = 4 }; // -namespace { - +namespace +{ + //======================================================================= + /*! + * \brief Auxiliary mesh + */ + struct TmpMesh: public SMESH_Mesh + { + TmpMesh() { + _isShapeToMesh = (_id = 0); + _myMeshDS = new SMESHDS_Mesh( _id, true ); + } + }; //======================================================================= /*! * \brief Quadrangle algorithm */ - struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D + class TQuadrangleAlgo : public StdMeshers_Quadrangle_2D { + typedef NCollection_DataMap< TopoDS_Face, FaceQuadStruct::Ptr > TFace2QuadMap; + TFace2QuadMap myFace2QuadMap; + TQuadrangleAlgo(SMESH_Gen* gen) : StdMeshers_Quadrangle_2D( gen->GetANewId(), gen) { } - static StdMeshers_Quadrangle_2D* instance( SMESH_Algo* fatherAlgo, - SMESH_MesherHelper* helper=0) + public: + + //================================================================================ + // Clear data of TQuadrangleAlgo at destruction + struct Cleaner + { + TQuadrangleAlgo* myAlgo; + + Cleaner(TQuadrangleAlgo* algo): myAlgo( algo ){} + ~Cleaner() { myAlgo->reset(); } + }; + + //================================================================================ + // Return TQuadrangleAlgo singleton + static TQuadrangleAlgo* instance( SMESH_Algo* fatherAlgo, + SMESH_MesherHelper* helper=0) { static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetGen() ); if ( helper && @@ -118,7 +146,123 @@ namespace { return algo; } + + //================================================================================ + // Clear collected data + void reset() + { + myFace2QuadMap.Clear(); + StdMeshers_Quadrangle_2D::myQuadList.clear(); + StdMeshers_Quadrangle_2D::myHelper = nullptr; + } + + //================================================================================ + /*! + * \brief Return FaceQuadStruct if a given FACE can be meshed by StdMeshers_Quadrangle_2D + */ + FaceQuadStruct::Ptr CheckNbEdges(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape ) + { + const TopoDS_Face& face = TopoDS::Face( theShape ); + if ( myFace2QuadMap.IsBound( face )) + return myFace2QuadMap.Find( face ); + + FaceQuadStruct::Ptr & resultQuad = * myFace2QuadMap.Bound( face, FaceQuadStruct::Ptr() ); + + FaceQuadStruct::Ptr quad = + StdMeshers_Quadrangle_2D::CheckNbEdges( theMesh, face, /*considerMesh=*/false, myHelper ); + if ( quad ) + { + // check if the quadrangle mesh would be valid + + // check existing 1D mesh + // int nbSegments[4], i = 0; + // for ( FaceQuadStruct::Side & side : quad->side ) + // nbSegments[ i++ ] = side.grid->NbSegments(); + // if ( nbSegments[0] > 0 && nbSegments[2] > 0 && nbSegments[0] != nbSegments[2] || + // nbSegments[1] > 0 && nbSegments[3] > 0 && nbSegments[1] != nbSegments[3] ) + // return resultQuad; + + int nbEdges = 0; + for ( FaceQuadStruct::Side & side : quad->side ) + nbEdges += side.grid->NbEdges(); + if ( nbEdges == 4 ) + return resultQuad = quad; + + TmpMesh mesh; + mesh.ShapeToMesh( face ); + SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); + SMESH_MesherHelper helper( mesh ); + helper.SetSubShape( face ); + helper.SetElementsOnShape( true ); + + // create nodes on all VERTEX'es + for ( TopExp_Explorer vert( face, TopAbs_VERTEX ); vert.More(); vert.Next() ) + mesh.GetSubMesh( vert.Current() )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + + FaceQuadStruct::Ptr tmpQuad( new FaceQuadStruct() ); + tmpQuad->side.resize( 4 ); + + // divide quad sides into halves at least + const SMDS_MeshNode* node; + for ( int iDir = 0; iDir < 2; ++iDir ) + { + StdMeshers_FaceSidePtr sides[2] = { quad->side[iDir], quad->side[iDir+2] }; + std::map< double, const SMDS_MeshNode* > nodes[2]; + for ( int iS : { 0, 1 } ) + { + node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex(), meshDS ); + nodes[iS].insert( std::make_pair( 0, node )); + double curLen = 0; + for ( int iE = 1; iE < sides[iS]->NbEdges(); ++iE ) + { + curLen += sides[iS]->EdgeLength( iE - 1 ); + double u = curLen / sides[iS]->Length(); + node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex( iE ), meshDS ); + nodes[iS ].insert( std::make_pair( u, node )); + nodes[1-iS].insert( std::make_pair( u, nullptr )); + } + nodes[iS].insert( std::make_pair( 0.5, nullptr )); + node = SMESH_Algo::VertexNode( sides[iS]->LastVertex(), meshDS ); + nodes[iS].insert( std::make_pair( 1, node )); + } + + for ( int iS : { 0, 1 } ) + { + UVPtStructVec sideNodes; + sideNodes.reserve( nodes[ iS ].size() ); + for ( auto & u_node : nodes[ iS ]) + { + if ( !u_node.second ) + { + gp_Pnt p = sides[iS]->Value3d( u_node.first ); + u_node.second = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + TopoDS_Edge edge; + double param = sides[iS]->Parameter( u_node.first, edge ); + meshDS->SetNodeOnEdge( u_node.second, edge, param ); + } + sideNodes.push_back( u_node.second ); + sideNodes.back().SetUV( helper.GetNodeUV( face, u_node.second )); + } + tmpQuad->side[ iS ? iDir+2 : iDir ] = StdMeshers_FaceSide::New( sideNodes, face ); + } + } + StdMeshers_Quadrangle_2D::myCheckOri = true; + StdMeshers_Quadrangle_2D::myQuadList.clear(); + StdMeshers_Quadrangle_2D::myQuadList.push_back( tmpQuad ); + StdMeshers_Quadrangle_2D::myHelper = &helper; + if ( StdMeshers_Quadrangle_2D::computeQuadDominant( mesh, face, tmpQuad ) && + StdMeshers_Quadrangle_2D::check()) + { + resultQuad = quad; + } + StdMeshers_Quadrangle_2D::myQuadList.clear(); + StdMeshers_Quadrangle_2D::myHelper = nullptr; + } + return resultQuad; + } }; + //======================================================================= /*! * \brief Algorithm projecting 1D mesh @@ -400,7 +544,7 @@ namespace { int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh, SMESH_MesherHelper* helper, - StdMeshers_Quadrangle_2D* quadAlgo) + TQuadrangleAlgo* quadAlgo) { int nbRemoved = 0; //SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS(); @@ -528,6 +672,22 @@ namespace { return nbSides; } + //================================================================================ + /*! + * \brief Count EDGEs ignoring degenerated ones + */ + //================================================================================ + + int CountEdges( const TopoDS_Face& face ) + { + int nbE = 0; + for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + if ( !SMESH_Algo::isDegenerated( TopoDS::Edge( edgeExp.Current() ))) + ++nbE; + + return nbE; + } + //================================================================================ /*! * \brief Set/get wire index to FaceQuadStruct @@ -559,6 +719,7 @@ namespace { } #endif } + } // namespace //======================================================================= @@ -617,6 +778,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh SMESH_MesherHelper helper( theMesh ); myHelper = &helper; myPrevBottomSM = 0; + TQuadrangleAlgo::Cleaner( TQuadrangleAlgo::instance( this )); int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false ); if ( nbSolids < 1 ) @@ -628,7 +790,6 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh // look for meshed FACEs ("source" FACEs) that must be prism bottoms list< TopoDS_Face > meshedFaces, notQuadMeshedFaces, notQuadFaces; const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 ); - //StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this ); for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF ) { const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); @@ -715,7 +876,8 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh return false; SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop ); - if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ) || + !myHelper->IsStructured( theMesh.GetSubMesh( prism.myTop ))) { meshedFaces.push_front( prism.myTop ); } @@ -919,7 +1081,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, SMESH_Mesh* mesh = myHelper->GetMesh(); - StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); + TQuadrangleAlgo* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); TopTools_MapOfShape faceMap; TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces; @@ -1465,8 +1627,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); DBGOUT( endl << "COMPUTE Prism " << meshDS->ShapeToIndex( thePrism.myShape3D )); - TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this ); - StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); + TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this ); + TQuadrangleAlgo* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); // SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true); // hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 )); @@ -2674,6 +2836,9 @@ bool StdMeshers_Prism_3D::allVerticalEdgesStraight( const Prism_3D::TPrismTopo& bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, const TopoDS_Face& theTgtFace) { + if ( CountEdges( theSrcFace ) != CountEdges( theTgtFace )) + return false; + TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this ); projector2D->myHyp.SetSourceFace( theSrcFace ); bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace ); @@ -2771,19 +2936,50 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() { struct EdgeWithNeighbors { - TopoDS_Edge _edge; - int _iBase; /* index in a WIRE with non-base EDGEs excluded */ - int _iL, _iR; /* used to connect edges in a base FACE */ - bool _isBase; /* is used in a base FACE */ - EdgeWithNeighbors(const TopoDS_Edge& E, int iE, int nbE, int shift, bool isBase ): - _edge( E ), _iBase( iE + shift ), - _iL( SMESH_MesherHelper::WrapIndex( iE-1, Max( 1, nbE )) + shift ), - _iR( SMESH_MesherHelper::WrapIndex( iE+1, Max( 1, nbE )) + shift ), + TopoDS_Edge _edge; + int _iBase; // index in a WIRE with non-base EDGEs excluded + int _iL, _iR; // used to connect PrismSide's + int _iE; // index in a WIRE + int _iLE, _iRE; // used to connect EdgeWithNeighbors's + bool _isBase; // is used in a base FACE + TopoDS_Vertex _vv[2]; // end VERTEXes + EdgeWithNeighbors(const TopoDS_Edge& E, + int iE, int nbE, int shift, + int iEE, int nbEE, int shiftE, + bool isBase, bool setVV ): + _edge( E ), + _iBase( iE + shift ), + _iL ( SMESH_MesherHelper::WrapIndex( iE-1, Max( 1, nbE )) + shift ), + _iR ( SMESH_MesherHelper::WrapIndex( iE+1, Max( 1, nbE )) + shift ), + _iE ( iEE + shiftE ), + _iLE( SMESH_MesherHelper::WrapIndex( iEE-1, Max( 1, nbEE )) + shiftE ), + _iRE( SMESH_MesherHelper::WrapIndex( iEE+1, Max( 1, nbEE )) + shiftE ), _isBase( isBase ) { + if ( setVV ) + { + Vertex( 0 ); + Vertex( 1 ); + } } EdgeWithNeighbors() {} bool IsInternal() const { return !_edge.IsNull() && _edge.Orientation() == TopAbs_INTERNAL; } + bool IsConnected( const EdgeWithNeighbors& edge, int iEnd ) const + { + return (( _vv[ iEnd ].IsSame( edge._vv[ 1 - iEnd ])) || + ( IsInternal() && _vv[ iEnd ].IsSame( edge._vv[ iEnd ]))); + } + bool IsConnected( const std::vector< EdgeWithNeighbors > & edges, int iEnd ) const + { + int iEdge = iEnd ? _iRE : _iLE; + return iEdge == _iE ? false : IsConnected( edges[ iEdge ], iEnd ); + } + const TopoDS_Vertex& Vertex( int iEnd ) + { + if ( _vv[ iEnd ].IsNull() ) + _vv[ iEnd ] = SMESH_MesherHelper::IthVertex( iEnd, _edge ); + return _vv[ iEnd ]; + } }; // PrismSide contains all FACEs linking a bottom EDGE with a top one. struct PrismSide @@ -2798,8 +2994,8 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() PrismSide *_leftSide; // neighbor sides PrismSide *_rightSide; bool _isInternal; // whether this side raises from an INTERNAL EDGE - void SetExcluded() { _leftSide = _rightSide = NULL; } - bool IsExcluded() const { return !_leftSide; } + //void SetExcluded() { _leftSide = _rightSide = NULL; } + //bool IsExcluded() const { return !_leftSide; } const TopoDS_Edge& Edge( int i ) const { return (*_edges)[ i ]._edge; @@ -2810,14 +3006,33 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() if ( E.IsSame( Edge( i ))) return i; return -1; } - bool IsSideFace( const TopoDS_Shape& face, const bool checkNeighbors ) const + const TopoDS_Vertex& Vertex( int iE, int iEnd ) const { - if ( _faces->Contains( face )) // avoid returning true for a prism top FACE - return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() )))); - + return (*_edges)[ iE ].Vertex( iEnd ); + } + bool HasVertex( const TopoDS_Vertex& V ) const + { + for ( size_t i = 0; i < _edges->size(); ++i ) + if ( V.IsSame( Vertex( i, 0 ))) return true; + return false; + } + bool IsSideFace( const TopTools_ListOfShape& faces, + const TopoDS_Face& avoidFace, + const bool checkNeighbors ) const + { + TopTools_ListIteratorOfListOfShape faceIt( faces ); + for ( ; faceIt.More(); faceIt.Next() ) + { + const TopoDS_Shape& face = faceIt.Value(); + if ( !face.IsSame( avoidFace )) + { + if ( _faces->Contains( face )) // avoid returning true for a prism top FACE + return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() )))); + } + } if ( checkNeighbors ) - return (( _leftSide && _leftSide->IsSideFace ( face, false )) || - ( _rightSide && _rightSide->IsSideFace( face, false ))); + return (( _leftSide && _leftSide->IsSideFace ( faces, avoidFace, false )) || + ( _rightSide && _rightSide->IsSideFace( faces, avoidFace, false ))); return false; } @@ -2827,20 +3042,39 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() * \brief Return another faces sharing an edge */ const TopoDS_Face & getAnotherFace( const TopoDS_Face& face, - const TopoDS_Edge& edge, - TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge) + const TopTools_ListOfShape& faces) { - TopTools_ListIteratorOfListOfShape faceIt( facesOfEdge.FindFromKey( edge )); + TopTools_ListIteratorOfListOfShape faceIt( faces ); for ( ; faceIt.More(); faceIt.Next() ) if ( !face.IsSame( faceIt.Value() )) return TopoDS::Face( faceIt.Value() ); return face; } + //-------------------------------------------------------------------------------- + /*! + * \brief Return another faces sharing an edge + */ + const TopoDS_Face & getAnotherFace( const TopoDS_Face& face, + const TopoDS_Edge& edge, + TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge) + { + return getAnotherFace( face, facesOfEdge.FindFromKey( edge )); + } //-------------------------------------------------------------------------------- /*! * \brief Return ordered edges of a face */ + //================================================================================ + /*! + * \brief Return ordered edges of a face + * \param [in] face - the face + * \param [out] edges - return edge (edges from which no vertical faces raise excluded) + * \param [in] facesOfEdge - faces of each edge + * \param [in] noHolesAllowed - are multiple wires allowed + */ + //================================================================================ + bool getEdges( const TopoDS_Face& face, vector< EdgeWithNeighbors > & edges, TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge, @@ -2856,11 +3090,10 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() if ( nbW > 1 && noHolesAllowed ) return false; - int iE, nbTot = 0, nbBase, iBase; list< TopoDS_Edge >::iterator e = ee.begin(); list< int >::iterator nbE = nbEdgesInWires.begin(); for ( ; nbE != nbEdgesInWires.end(); ++nbE ) - for ( iE = 0; iE < *nbE; ++e, ++iE ) + for ( int iE = 0; iE < *nbE; ++e, ++iE ) if ( SMESH_Algo::isDegenerated( *e )) // degenerated EDGE is never used { e = --ee.erase( e ); @@ -2868,6 +3101,7 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() --iE; } + int iE, nbTot = 0, iBase, nbBase, nbTotBase = 0; vector isBase; edges.clear(); e = ee.begin(); @@ -2883,40 +3117,51 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() } for ( iBase = 0, iE = 0; iE < *nbE; ++e, ++iE ) { - edges.push_back( EdgeWithNeighbors( *e, iBase, nbBase, nbTot, isBase[ iE ] )); + edges.push_back( EdgeWithNeighbors( *e, + iBase, nbBase, nbTotBase, + iE, *nbE, nbTot, + isBase[ iE ], nbW > 1 )); iBase += isBase[ iE ]; } - nbTot += nbBase; + nbTot += *nbE; + nbTotBase += nbBase; } - if ( nbTot == 0 ) + if ( nbTotBase == 0 ) return false; - // IPAL53099. Set correct neighbors to INTERNAL EDGEs, which can be connected to - // EDGEs of the outer WIRE but this fact can't be detected by their order. + // IPAL53099, 54416. Set correct neighbors to INTERNAL EDGEs if ( nbW > 1 ) { int iFirst = 0, iLast; for ( nbE = nbEdgesInWires.begin(); nbE != nbEdgesInWires.end(); ++nbE ) { iLast = iFirst + *nbE - 1; - TopoDS_Vertex vv[2] = { SMESH_MesherHelper::IthVertex( 0, edges[ iFirst ]._edge ), - SMESH_MesherHelper::IthVertex( 1, edges[ iLast ]._edge ) }; - bool isConnectOk = ( vv[0].IsSame( vv[1] )); + bool isConnectOk = ( edges[ iFirst ].IsConnected( edges, 0 ) && + edges[ iFirst ].IsConnected( edges, 1 )); if ( !isConnectOk ) { - edges[ iFirst ]._iL = edges[ iFirst ]._iBase; // connect to self - edges[ iLast ]._iR = edges[ iLast ]._iBase; - - // look for an EDGE of the outer WIREs connected to vv - TopoDS_Vertex v0, v1; - for ( iE = 0; iE < iFirst; ++iE ) + for ( iE = iFirst; iE <= iLast; ++iE ) { - v0 = SMESH_MesherHelper::IthVertex( 0, edges[ iE ]._edge ); - v1 = SMESH_MesherHelper::IthVertex( 1, edges[ iE ]._edge ); - if ( vv[0].IsSame( v0 ) || vv[0].IsSame( v1 )) - edges[ iFirst ]._iL = edges[ iE ]._iBase; - if ( vv[1].IsSame( v0 ) || vv[1].IsSame( v1 )) - edges[ iLast ]._iR = edges[ iE ]._iBase; + if ( !edges[ iE ]._isBase ) + continue; + int* iNei[] = { & edges[ iE ]._iL, + & edges[ iE ]._iR }; + for ( int iV = 0; iV < 2; ++iV ) + { + if ( edges[ iE ].IsConnected( edges, iV )) + continue; // Ok - connected to a neighbor EDGE + + // look for a connected EDGE + bool found = false; + for ( int iE2 = 0, nbE = edges.size(); iE2 < nbE && !found; ++iE2 ) + if (( iE2 != iE ) && + ( found = edges[ iE ].IsConnected( edges[ iE2 ], iV ))) + { + *iNei[ iV ] = edges[ iE2 ]._iBase; + } + if ( !found ) + *iNei[ iV ] = edges[ iE ]._iBase; // connect to self + } } } iFirst += *nbE; @@ -3049,11 +3294,11 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA } bool isOK = true; // ok for a current botF - bool isAdvanced = true; // is new data found in a current loop + bool hasAdvanced = true; // is new data found in a current loop int nbFoundSideFaces = 0; - for ( int iLoop = 0; isOK && isAdvanced; ++iLoop ) + for ( int iLoop = 0; isOK && hasAdvanced; ++iLoop ) { - isAdvanced = false; + hasAdvanced = false; for ( size_t iS = 0; iS < sides.size() && isOK; ++iS ) { PrismSide& side = sides[ iS ]; @@ -3065,19 +3310,32 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA // find vertical EDGEs --- EDGEs shared with neighbor side FACEs for ( int is2nd = 0; is2nd < 2 && isOK; ++is2nd ) // 2 adjacent neighbors { - int di = is2nd ? 1 : -1; const PrismSide* adjSide = is2nd ? side._rightSide : side._leftSide; + if ( side._isInternal ) + { + const TopoDS_Vertex& V = side.Vertex( side._iBotEdge, is2nd ); + bool lHasV = side._leftSide ->HasVertex( V ); + bool rHasV = side._rightSide->HasVertex( V ); + if ( lHasV == rHasV ) + adjSide = ( &side == side._leftSide ) ? side._rightSide : side._leftSide; + else + adjSide = ( rHasV ) ? side._rightSide : side._leftSide; + } + int di = is2nd ? 1 : -1; for ( size_t i = 1; i < side._edges->size(); ++i ) { int iE = SMESH_MesherHelper::WrapIndex( i*di + side._iBotEdge, side._edges->size()); if ( side._isCheckedEdge[ iE ] ) continue; - const TopoDS_Edge& vertE = side.Edge( iE ); - const TopoDS_Shape& neighborF = getAnotherFace( side._face, vertE, facesOfEdge ); - bool isEdgeShared = (( adjSide->IsSideFace( neighborF, side._isInternal )) || - ( adjSide == &side && neighborF.IsSame( side._face )) ); + const TopoDS_Edge& vertE = side.Edge( iE ); + const TopTools_ListOfShape& neighborFF = facesOfEdge.FindFromKey( vertE ); + bool isEdgeShared = (( adjSide->IsSideFace( neighborFF, side._face, + side._isInternal )) || + ( adjSide == &side && + side._face.IsSame( getAnotherFace( side._face, + neighborFF )))); if ( isEdgeShared ) // vertE is shared with adjSide { - isAdvanced = true; + hasAdvanced = true; side._isCheckedEdge[ iE ] = true; side._nbCheckedEdges++; int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges; @@ -3145,7 +3403,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA const int nbE = side._edges->size(); if ( nbE >= 4 ) { - isAdvanced = true; + hasAdvanced = true; ++nbFoundSideFaces; side._iBotEdge = side.FindEdge( side._topEdge ); side._isCheckedEdge.clear(); @@ -3175,7 +3433,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA cerr << "BUG: infinite loop in StdMeshers_Prism_3D::IsApplicable()" << endl; #endif } - } // while isAdvanced + } // while hasAdvanced if ( isOK && sides[0]._faces->Extent() > 1 ) { @@ -3186,12 +3444,20 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA } else { + // check that all face columns end up at the same top face const TopoDS_Shape& topFace = sides[0]._faces->FindKey( nbFaces ); size_t iS; for ( iS = 1; iS < sides.size(); ++iS ) if ( ! sides[ iS ]._faces->Contains( topFace )) break; - prismDetected = ( iS == sides.size() ); + if (( prismDetected = ( iS == sides.size() ))) + { + // check that bottom and top faces has equal nb of edges + TEdgeWithNeighborsVec& topEdges = faceEdgesVec[ allFaces.FindIndex( topFace )]; + if ( topEdges.empty() ) + getEdges( TopoDS::Face( topFace ), topEdges, facesOfEdge, /*noHoles=*/false ); + prismDetected = ( botEdges.size() == topEdges.size() ); + } } } } // loop on allFaces @@ -3989,10 +4255,10 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & //================================================================================ /*! - * \brief Check curve orientation of a bootom edge + * \brief Check curve orientation of a bottom edge * \param meshDS - mesh DS * \param columnsMap - node columns map of side face - * \param bottomEdge - the bootom edge + * \param bottomEdge - the bottom edge * \param sideFaceID - side face in-block ID * \retval bool - true if orientation coincide with in-block forward orientation */ @@ -5121,10 +5387,10 @@ bool StdMeshers_Sweeper::ComputeNodesByTrsf( const double tol, for ( ++zS, --zT; zS < zTgt; ++zS, --zT ) // vertical loop on layers { // invert transformation - if ( !trsfOfLayer[ zS+1 ].Invert() ) - trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute - if ( !trsfOfLayer[ zT-1 ].Invert() ) - trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D(); + //if ( !trsfOfLayer[ zS+1 ].Invert() ) + trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute + //if ( !trsfOfLayer[ zT-1 ].Invert() ) + trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D(); // project internal nodes and compute bnd error for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) @@ -5363,15 +5629,34 @@ void StdMeshers_Sweeper::fillZColumn( TZColumn& zColumn, void StdMeshers_Sweeper::prepareTopBotDelaunay() { + SMESH_MesherHelper* helper[2] = { myHelper, myHelper }; + SMESH_MesherHelper botHelper( *myHelper->GetMesh() ); + SMESH_MesherHelper topHelper( *myHelper->GetMesh() ); + const SMDS_MeshNode* intBotNode = 0; + const SMDS_MeshNode* intTopNode = 0; + if ( myHelper->HasSeam() || myHelper->HasDegeneratedEdges() ) // use individual helpers + { + botHelper.SetSubShape( myBotFace ); + topHelper.SetSubShape( myTopFace ); + helper[0] = & botHelper; + helper[1] = & topHelper; + if ( !myIntColumns.empty() ) + { + TNodeColumn& nodes = *myIntColumns[ myIntColumns.size()/2 ]; + intBotNode = nodes[0]; + intTopNode = nodes.back(); + } + } + UVPtStructVec botUV( myBndColumns.size() ); UVPtStructVec topUV( myBndColumns.size() ); for ( size_t i = 0; i < myBndColumns.size(); ++i ) { TNodeColumn& nodes = *myBndColumns[i]; botUV[i].node = nodes[0]; - botUV[i].SetUV( myHelper->GetNodeUV( myBotFace, nodes[0] )); + botUV[i].SetUV( helper[0]->GetNodeUV( myBotFace, nodes[0], intBotNode )); topUV[i].node = nodes.back(); - topUV[i].SetUV( myHelper->GetNodeUV( myTopFace, nodes.back() )); + topUV[i].SetUV( helper[1]->GetNodeUV( myTopFace, nodes.back(), intTopNode )); botUV[i].node->setIsMarked( true ); } TopoDS_Edge dummyE;