From 3ddacb9798d8f204eb3d71531cd7a4a7b295a207 Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 12 Nov 2014 18:35:28 +0300 Subject: [PATCH] To compute mesh in SALOME_TESTS/Grids/geom/bugs_15/R7 and other tests of "Extrusion 3D" mesher --- src/SMESH/SMESH_MesherHelper.cxx | 10 +- src/SMESH/SMESH_MesherHelper.hxx | 2 +- src/StdMeshers/StdMeshers_Prism_3D.cxx | 159 ++++++++++----- src/StdMeshers/StdMeshers_Prism_3D.hxx | 5 +- src/StdMeshers/StdMeshers_ProjectionUtils.cxx | 184 ++++++++++-------- src/StdMeshers/StdMeshers_Projection_2D.cxx | 67 ++++--- 6 files changed, 257 insertions(+), 170 deletions(-) diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index 0d4173c28..eac668694 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -941,7 +941,7 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, int shapeID = n->getshapeId(); bool infinit = Precision::IsInfinite( u ); bool zero = ( u == 0. ); - if ( force || toCheckPosOnShape( shapeID ) || infinit || zero ) + if ( force || infinit || zero || toCheckPosOnShape( shapeID )) { TopLoc_Location loc; double f,l; Handle(Geom_Curve) curve = BRep_Tool::Curve( E,loc,f,l ); @@ -958,7 +958,7 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, gp_Pnt nodePnt = SMESH_TNodeXYZ( n ); if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); gp_Pnt curvPnt; - double dist = u; + double dist = 2*tol; if ( !infinit ) { curvPnt = curve->Value( u ); @@ -2559,7 +2559,8 @@ bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) //purpose : Return true if 2D mesh on FACE is ditorted //======================================================================= -bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM ) +bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM, + bool checkUV) { if ( !faceSM || faceSM->GetSubShape().ShapeType() != TopAbs_FACE ) return false; @@ -2577,6 +2578,7 @@ bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM ) double prevArea2D = 0; vector< const SMDS_MeshNode* > nodes; vector< gp_XY > uv; + bool* toCheckUV = checkUV ? & checkUV : 0; while ( faceIt->more() && !haveBadFaces ) { const SMDS_MeshElement* face = faceIt->next(); @@ -2608,7 +2610,7 @@ bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM ) // get UVs uv.resize( nodes.size() ); for ( size_t i = 0; i < nodes.size(); ++i ) - uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode ); + uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode, toCheckUV ); // compare orientation of triangles for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT ) diff --git a/src/SMESH/SMESH_MesherHelper.hxx b/src/SMESH/SMESH_MesherHelper.hxx index ae6767d30..164861c32 100644 --- a/src/SMESH/SMESH_MesherHelper.hxx +++ b/src/SMESH/SMESH_MesherHelper.hxx @@ -120,7 +120,7 @@ class SMESH_EXPORT SMESH_MesherHelper /*! * \brief Return true if 2D mesh on FACE is distored */ - static bool IsDistorted2D( SMESH_subMesh* faceSM ); + static bool IsDistorted2D( SMESH_subMesh* faceSM, bool checkUV=false ); /*! * \brief Returns true if given node is medium diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 62f538d84..8681b78d9 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -689,6 +689,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh list< Prism_3D::TPrismTopo > meshedPrism; list< TopoDS_Face > suspectSourceFaces; TopTools_ListIteratorOfListOfShape solidIt; + bool selectBottom = false; while ( meshedSolids.Extent() < nbSolids ) { @@ -709,7 +710,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { prism.Clear(); prism.myBottom = face; - if ( !initPrism( prism, solid ) || + if ( !initPrism( prism, solid, selectBottom ) || !compute( prism )) return false; @@ -762,15 +763,24 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh while ( const TopoDS_Shape* f = faceIt->next() ) { const TopoDS_Face& candidateF = TopoDS::Face( *f ); + if ( candidateF.IsSame( wFace )) continue; + // select a source FACE: prismIt->myBottom or prismIt->myTop + TopoDS_Face sourceF = prismIt->myBottom; + for ( TopExp_Explorer v( prismIt->myTop, TopAbs_VERTEX ); v.More(); v.Next() ) + if ( myHelper->IsSubShape( v.Current(), candidateF )) { + sourceF = prismIt->myTop; + break; + } prism.Clear(); - prism.myBottom = candidateF; + prism.myBottom = candidateF; mySetErrorToSM = false; if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) && - myHelper->IsSubShape( candidateF, solid ) && + myHelper ->IsSubShape( candidateF, solid ) && !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() && - initPrism( prism, solid ) && + initPrism( prism, solid, /*selectBottom=*/false ) && !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() && - project2dMesh( prismIt->myBottom, candidateF)) + !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() && + project2dMesh( sourceF, prism.myBottom )) { mySetErrorToSM = true; if ( !compute( prism )) @@ -780,6 +790,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { meshedFaces.push_front( prism.myTop ); meshedFaces.push_front( prism.myBottom ); + selectBottom = false; } meshedPrism.push_back( prism ); meshedSolids.Add( solid ); @@ -802,6 +813,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh if ( meshedFaces.empty() ) { meshedFaces.splice( meshedFaces.end(), suspectSourceFaces ); + selectBottom = true; } // find FACEs with local 1D hyps, which has to be computed by now, @@ -822,6 +834,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { if ( !meshedFaces.empty() ) meshedFaces.pop_back(); meshedFaces.push_back( face ); // lower priority + selectBottom = true; prevNbFaces = nbFaces; } } @@ -836,6 +849,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); if ( !faceSM->IsEmpty() ) { meshedFaces.push_front( face ); // higher priority + selectBottom = true; break; } else { @@ -867,6 +881,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh meshedFaces.push_front( prism.myBottom ); meshedPrism.push_back( prism ); meshedSolids.Add( solid.Current() ); + selectBottom = true; } mySetErrorToSM = true; } @@ -1071,7 +1086,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; const TopoDS_Edge & topE = topSide->Edge( 0 ); if ( !myHelper->IsSubShape( topE, thePrism.myTop )) - return toSM( error( TCom("Wrong source face (#") << shapeID( thePrism.myBottom ))); + return toSM( error( TCom("Wrong source face: #") << shapeID( thePrism.myBottom ))); } return true; @@ -1088,13 +1103,21 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) if ( _computeCanceled ) return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); + // Assure the bottom is meshed + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if ( ! NSProjUtils::MakeComputed( botSM )) + return error( COMPERR_BAD_INPUT_MESH, + TCom( "No mesher defined to compute the face #") + << shapeID( thePrism.myBottom )); + // Make all side FACEs of thePrism meshed with quads if ( !computeWalls( thePrism )) return false; // Analyse mesh and geometry to find all block sub-shapes and submeshes - // (after fixing IPAL52499 myBlock is used only as a holder of boundary nodes - // and location of internal nodes is computed by StdMeshers_Sweeper) + // (after fixing IPAL52499 myBlock is used as a holder of boundary nodes + // and for 2D projection in hard cases where StdMeshers_Projection_2D fails; + // location of internal nodes is usually computed by StdMeshers_Sweeper) if ( !myBlock.Init( myHelper, thePrism )) return toSM( error( myBlock.GetError())); @@ -1123,6 +1146,7 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // Projections on the top and bottom faces are taken from nodes existing // on these faces; find correspondence between bottom and top nodes + myUseBlock = false; myBotToColumnMap.clear(); if ( !assocOrProjBottom2Top( bottomToTopTrsf, thePrism ) ) // it also fills myBotToColumnMap return false; @@ -1132,27 +1156,31 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // use transformation (issue 0020680, IPAL0052499) StdMeshers_Sweeper sweeper; + double tol; - // load boundary nodes - bool dummy; - list< TopoDS_Edge >::const_iterator edge = thePrism.myBottomEdges.begin(); - for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + if ( !myUseBlock ) { - int edgeID = meshDS->ShapeToIndex( *edge ); - TParam2ColumnMap* u2col = const_cast - ( myBlock.GetParam2ColumnMap( edgeID, dummy )); - TParam2ColumnMap::iterator u2colIt = u2col->begin(); - for ( ; u2colIt != u2col->end(); ++u2colIt ) - sweeper.myBndColumns.push_back( & u2colIt->second ); - } - // load node columns inside the bottom face - TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); - for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) - sweeper.myIntColumns.push_back( & bot_column->second ); + // load boundary nodes into sweeper + bool dummy; + list< TopoDS_Edge >::const_iterator edge = thePrism.myBottomEdges.begin(); + for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + { + int edgeID = meshDS->ShapeToIndex( *edge ); + TParam2ColumnMap* u2col = const_cast + ( myBlock.GetParam2ColumnMap( edgeID, dummy )); + TParam2ColumnMap::iterator u2colIt = u2col->begin(); + for ( ; u2colIt != u2col->end(); ++u2colIt ) + sweeper.myBndColumns.push_back( & u2colIt->second ); + } + // load node columns inside the bottom face + TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); + for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) + sweeper.myIntColumns.push_back( & bot_column->second ); - const double tol = getSweepTolerance( thePrism ); + tol = getSweepTolerance( thePrism ); + } - if ( sweeper.ComputeNodes( *myHelper, tol )) + if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol )) { } else // use block approach @@ -1528,7 +1556,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) { const TopoDS_Face& face = (*quad)->face; - SMESH_subMesh* fSM = mesh->GetSubMesh( face ); + SMESH_subMesh* fSM = mesh->GetSubMesh( face ); if ( ! fSM->IsMeshComputed() ) { // Top EDGEs must be projections from the bottom ones @@ -1938,8 +1966,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf NSProjUtils::TShapeShapeMap shape2ShapeMap; const bool sameTopo = NSProjUtils::FindSubShapeAssociation( thePrism.myBottom, myHelper->GetMesh(), - thePrism.myTop, myHelper->GetMesh(), - shape2ShapeMap); + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap); if ( !sameTopo ) for ( size_t iQ = 0; iQ < thePrism.myWallQuads.size(); ++iQ ) { @@ -1951,10 +1979,10 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf for ( int iE = 0; iE < botSide->NbEdges(); ++iE ) { NSProjUtils::InsertAssociation( botSide->Edge( iE ), - topSide->Edge( iE ), shape2ShapeMap ); + topSide->Edge( iE ), shape2ShapeMap ); NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )), - myHelper->IthVertex( 0, topSide->Edge( iE )), - shape2ShapeMap ); + myHelper->IthVertex( 0, topSide->Edge( iE )), + shape2ShapeMap ); } } else @@ -1969,7 +1997,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf vt.IsSame( sideT->LastVertex() )) { NSProjUtils::InsertAssociation( botSide->Edge( 0 ), - topSide->Edge( 0 ), shape2ShapeMap ); + topSide->Edge( 0 ), shape2ShapeMap ); NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); } vb = myHelper->IthVertex( 1, botSide->Edge( botSide->NbEdges()-1 )); @@ -1980,8 +2008,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf vt.IsSame( sideT->LastVertex() )) { NSProjUtils::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ), - topSide->Edge( topSide->NbEdges()-1 ), - shape2ShapeMap ); + topSide->Edge( topSide->NbEdges()-1 ), + shape2ShapeMap ); NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); } } @@ -1990,8 +2018,8 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf // Find matching nodes of top and bottom faces n2nMapPtr = & n2nMap; if ( ! NSProjUtils::FindMatchingNodesOnFaces( thePrism.myBottom, myHelper->GetMesh(), - thePrism.myTop, myHelper->GetMesh(), - shape2ShapeMap, n2nMap )) + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap, n2nMap )) { if ( sameTopo ) return toSM( error(TCom("Mesh on faces #") << botSM->GetId() @@ -2014,7 +2042,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf continue; // wall columns are contained in myBlock // create node column Prism_3D::TNode bN( botNode ); - TNode2ColumnMap::iterator bN_col = + TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); @@ -2038,6 +2066,11 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom { return true; } + NSProjUtils::TNodeNodeMap& n2nMap = + (NSProjUtils::TNodeNodeMap&) TProjction2dAlgo::instance( this )->GetNodesMap(); + n2nMap.clear(); + + myUseBlock = true; SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); @@ -2047,7 +2080,13 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( topSMDS && topSMDS->NbElements() > 0 ) - topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + { + //topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + for ( SMDS_ElemIteratorPtr eIt = topSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), topSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = topSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), topSMDS, /*fromGroups=*/false ); + } const TopoDS_Face& botFace = thePrism.myBottom; // oriented within const TopoDS_Face& topFace = thePrism.myTop; // the 3D SHAPE @@ -2119,6 +2158,8 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom column.front() = botNode; column.back() = topNode; + n2nMap.insert( n2nMap.end(), make_pair( botNode, topNode )); + if ( _computeCanceled ) return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); } @@ -2270,6 +2311,15 @@ bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace ); SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace ); + if ( !ok && tgtSM->GetSubMeshDS() ) { + //tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh* tgtSMDS = tgtSM->GetSubMeshDS(); + for ( SMDS_ElemIteratorPtr eIt = tgtSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), tgtSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = tgtSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), tgtSMDS, /*fromGroups=*/false ); + } tgtSM->ComputeStateEngine ( SMESH_subMesh::CHECK_COMPUTE_STATE ); tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); @@ -2785,7 +2835,8 @@ void StdMeshers_PrismAsBlock::Clear() //======================================================================= bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, - const TopoDS_Shape& shape3D) + const TopoDS_Shape& shape3D, + const bool selectBottom) { myHelper->SetSubShape( shape3D ); @@ -2884,19 +2935,23 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, // use thePrism.myBottom if ( !thePrism.myBottom.IsNull() ) { - if ( botSM ) { + if ( botSM ) { // <-- not quad geom or mesh on botSM if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { std::swap( botSM, topSM ); - if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) - return toSM( error( COMPERR_BAD_INPUT_MESH, - "Incompatible non-structured sub-meshes")); + if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { + if ( !selectBottom ) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Incompatible non-structured sub-meshes")); + std::swap( botSM, topSM ); + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + } } } - else { + else if ( !selectBottom ) { botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); } } - else if ( !botSM ) // find a proper bottom + if ( !botSM ) // find a proper bottom { // composite walls or not prism shape for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() ) @@ -2906,11 +2961,17 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, { thePrism.Clear(); thePrism.myBottom = TopoDS::Face( f.Current() ); - if ( initPrism( thePrism, shape3D )) + if ( initPrism( thePrism, shape3D, /*selectBottom=*/false )) + { + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + topSM = myHelper->GetMesh()->GetSubMesh( thePrism.myTop ); + if ( botSM->IsEmpty() && !topSM->IsEmpty() ) + thePrism.SetUpsideDown(); return true; + } } - return toSM( error( COMPERR_BAD_SHAPE )); } + return toSM( error( COMPERR_BAD_SHAPE )); } // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) @@ -2943,7 +3004,7 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, thePrism.myNbEdgesInWires, V000 ); // Get Wall faces corresponding to the ordered bottom edges and the top FACE - if ( !getWallFaces( thePrism, nbFaces )) + if ( !getWallFaces( thePrism, nbFaces )) // it also sets thePrism.myTop return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces")); if ( topSM ) @@ -3887,7 +3948,7 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, TopoDS_Shape s = myHelper.GetSubShapeByNode( nn[0], myHelper.GetMeshDS() ); if ( s.ShapeType() != TopAbs_EDGE ) s = myHelper.GetSubShapeByNode( nn[2], myHelper.GetMeshDS() ); - if ( s.ShapeType() == TopAbs_EDGE ) + if ( !s.IsNull() && s.ShapeType() == TopAbs_EDGE ) edge = TopoDS::Edge( s ); } if ( !edge.IsNull() ) diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx index 6c7c52fe1..5d99375a9 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.hxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -482,7 +482,9 @@ public: * \brief Analyse shape geometry and mesh. * If there are triangles on one of faces, it becomes 'bottom' */ - bool initPrism(Prism_3D::TPrismTopo& thePrism, const TopoDS_Shape& theSolid); + bool initPrism(Prism_3D::TPrismTopo& thePrism, + const TopoDS_Shape& theSolid, + const bool selectBottom = true); /*! * \brief Fill thePrism.myWallQuads and thePrism.myTopEdges @@ -556,6 +558,7 @@ private: bool myProjectTriangles; bool mySetErrorToSM; + bool myUseBlock; StdMeshers_PrismAsBlock myBlock; SMESH_MesherHelper* myHelper; diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index f4c233e3e..00c925785 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -1942,97 +1942,109 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // 2. face sets - set Elems1, Elems2; - for ( int is2 = 0; is2 < 2; ++is2 ) + int assocRes; + for ( int iAttempt = 0; iAttempt < 2; ++iAttempt ) { - set & elems = is2 ? Elems2 : Elems1; - SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; - SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; - const TopoDS_Face & face = is2 ? face2 : face1; - SMDS_ElemIteratorPtr eIt = sm->GetElements(); - - if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) - { - while ( eIt->more() ) elems.insert( eIt->next() ); - } - else + set Elems1, Elems2; + for ( int is2 = 0; is2 < 2; ++is2 ) { - // the only suitable edge is seam, i.e. it is a sphere. - // FindMatchingNodes() will not know which way to go from any edge. - // So we ignore all faces having nodes on edges or vertices except - // one of faces sharing current start nodes - - // find a face to keep - const SMDS_MeshElement* faceToKeep = 0; - const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; - const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; - TIDSortedElemSet inSet, notInSet; - - const SMDS_MeshElement* f1 = - SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); - notInSet.insert( f1 ); - - const SMDS_MeshElement* f2 = - SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); - - // select a face with less UV of vNode - const SMDS_MeshNode* notSeamNode[2] = {0, 0}; - for ( int iF = 0; iF < 2; ++iF ) { - const SMDS_MeshElement* f = ( iF ? f2 : f1 ); - for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - if ( !helper->IsSeamShape( node->getshapeId() )) - notSeamNode[ iF ] = node; - } + set & elems = is2 ? Elems2 : Elems1; + SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + const TopoDS_Face & face = is2 ? face2 : face1; + SMDS_ElemIteratorPtr eIt = sm->GetElements(); + + if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) + { + while ( eIt->more() ) elems.insert( elems.end(), eIt->next() ); } - gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); - gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); - if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) - faceToKeep = f2; else - faceToKeep = f1; - - // fill elem set - elems.insert( faceToKeep ); - while ( eIt->more() ) { - const SMDS_MeshElement* f = eIt->next(); - int nbNodes = f->NbNodes(); - if ( f->IsQuadratic() ) - nbNodes /= 2; - bool onBnd = false; - for ( int i = 0; !onBnd && i < nbNodes; ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + { + // the only suitable edge is seam, i.e. it is a sphere. + // FindMatchingNodes() will not know which way to go from any edge. + // So we ignore all faces having nodes on edges or vertices except + // one of faces sharing current start nodes + + // find a face to keep + const SMDS_MeshElement* faceToKeep = 0; + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; + TIDSortedElemSet inSet, notInSet; + + const SMDS_MeshElement* f1 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); + notInSet.insert( f1 ); + + const SMDS_MeshElement* f2 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); + + // select a face with less UV of vNode + const SMDS_MeshNode* notSeamNode[2] = {0, 0}; + for ( int iF = 0; iF < 2; ++iF ) { + const SMDS_MeshElement* f = ( iF ? f2 : f1 ); + for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + if ( !helper->IsSeamShape( node->getshapeId() )) + notSeamNode[ iF ] = node; + } } - if ( !onBnd ) - elems.insert( f ); - } - // add also faces adjacent to faceToKeep - int nbNodes = faceToKeep->NbNodes(); - if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; - notInSet.insert( f1 ); - notInSet.insert( f2 ); - for ( int i = 0; i < nbNodes; ++i ) { - const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); - const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); - f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); - if ( f1 ) - elems.insert( f1 ); - } - } // case on a sphere - } // loop on 2 faces - - // int quadFactor = (*Elems1.begin())->IsQuadratic() ? 2 : 1; - - node1To2Map.clear(); - int res = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, - vNode1, vNode2, - eNode1[0], eNode2[0], - node1To2Map); - if ( res != SMESH_MeshEditor::SEW_OK ) - RETURN_BAD_RESULT("FindMatchingNodes() result " << res ); + gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); + gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); + if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) + faceToKeep = f2; + else + faceToKeep = f1; + + // fill elem set + elems.insert( faceToKeep ); + while ( eIt->more() ) { + const SMDS_MeshElement* f = eIt->next(); + int nbNodes = f->NbNodes(); + if ( f->IsQuadratic() ) + nbNodes /= 2; + bool onBnd = false; + for ( int i = 0; !onBnd && i < nbNodes; ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + } + if ( !onBnd ) + elems.insert( f ); + } + // add also faces adjacent to faceToKeep + int nbNodes = faceToKeep->NbNodes(); + if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; + notInSet.insert( f1 ); + notInSet.insert( f2 ); + for ( int i = 0; i < nbNodes; ++i ) { + const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); + const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); + f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); + if ( f1 ) + elems.insert( f1 ); + } + } // case on a sphere + } // loop on 2 faces + + node1To2Map.clear(); + assocRes = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, + vNode1, vNode2, + eNode1[0], eNode2[0], + node1To2Map); + if (( assocRes != SMESH_MeshEditor::SEW_OK ) && + ( eNode1[1] || eNode2[1] )) // there is another node to try (on a closed EDGE) + { + node1To2Map.clear(); + if ( eNode1[1] ) std::swap( eNode1[0], eNode1[1] ); + else std::swap( eNode2[0], eNode2[1] ); + continue; // one more attempt + } + + break; + } + if ( assocRes != SMESH_MeshEditor::SEW_OK ) + RETURN_BAD_RESULT("FindMatchingNodes() result " << assocRes ); // On a sphere, add matching nodes on the edge diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx index f8dd75016..23732bd6e 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -568,6 +568,7 @@ namespace { vector< gp_XYZ > srcPnts, tgtPnts; srcPnts.reserve( totNbSeg ); tgtPnts.reserve( totNbSeg ); + gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 ); for ( size_t iW = 0; iW < srcWires.size(); ++iW ) { const double minSegLen = srcWires[iW]->Length() / totNbSeg; @@ -584,6 +585,8 @@ namespace { tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() ); srcU += srcDu; tgtU += tgtDu; + srcBC += srcPnts.back(); + tgtBC += tgtPnts.back(); } } } @@ -596,6 +599,8 @@ namespace { const int nbTestPnt = 20; const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); // check boundary + gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol ); for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) { gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] ); @@ -606,8 +611,8 @@ namespace { { BRepAdaptor_Surface srcSurf( srcFace ); gp_Pnt srcP = - srcSurf.Value( 0.5 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), - 0.5 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); + srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), + 0.123 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); gp_Pnt tgtTrsfP = trsf.Transform( srcP ); TopLoc_Location loc; GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( tgtFace, loc, 0.1*tol ); @@ -888,10 +893,9 @@ namespace { case SMDS_TOP_EDGE: { TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() ); TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true )); - tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge )); - double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode ); + double U = Precision::Infinite(); helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion()); - n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U ))); + tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U ); break; } case SMDS_TOP_VERTEX: { @@ -922,12 +926,12 @@ namespace { */ //================================================================================ - void fixDistortedFaces( SMESH_MesherHelper& helper, + bool fixDistortedFaces( SMESH_MesherHelper& helper, TSideVector& tgtWires ) { SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() ); - if ( helper.IsDistorted2D( faceSM )) + if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false )) { SMESH_MeshEditor editor( helper.GetMesh() ); SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS(); @@ -965,7 +969,12 @@ namespace { set fixedNodes; editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + helper.ToFixNodeParameters( true ); + + return !helper.IsDistorted2D( faceSM, /*checkUV=*/true ); } + return true; } } // namespace @@ -1048,25 +1057,28 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( err && !err->IsOK() ) return error( err ); - bool done = false; + bool projDone = false; - if ( !done ) + if ( !projDone ) { // try to project from the same face with different location - done = projectPartner( tgtFace, srcFace, tgtWires, srcWires, - shape2ShapeMap, _src2tgtNodes, is1DComputed ); + projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed ); } - if ( !done ) + if ( !projDone ) { // projection in case if the faces are similar in 2D space - done = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, - shape2ShapeMap, _src2tgtNodes, is1DComputed); + projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed); } SMESH_MesherHelper helper( theMesh ); helper.SetSubShape( tgtFace ); - if ( !done ) + // it will remove mesh built on edges and vertices in failure case + MeshCleaner cleaner( tgtSubMesh ); + + if ( !projDone ) { _src2tgtNodes.clear(); // -------------------- @@ -1166,10 +1178,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) return error("Can't make mesh by source mesh pattern"); - // it will remove mesh built by pattern mapper on edges and vertices - // in failure case - MeshCleaner cleaner( tgtSubMesh ); - // ------------------------------------------------------------------------- // mapper doesn't take care of nodes already existing on edges and vertices, // so we must merge nodes created by it with existing ones @@ -1329,14 +1337,6 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() ) return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces"); - - // ---------------------------------------------------------------- - // The mapper can create distorted faces by placing nodes out of the FACE - // boundary -- fix bad faces by smoothing - // ---------------------------------------------------------------- - - fixDistortedFaces( helper, tgtWires ); - // ---------------------------------------------------------------- // The mapper can't create quadratic elements, so convert if needed // ---------------------------------------------------------------- @@ -1355,11 +1355,18 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false); } - cleaner.Release(); // not to remove mesh - } // end of projection using Pattern mapping + if ( !projDone || is1DComputed ) + // ---------------------------------------------------------------- + // The mapper can create distorted faces by placing nodes out of the FACE + // boundary, also bad face can be created if EDGEs already discretized + // --> fix bad faces by smoothing + // ---------------------------------------------------------------- + if ( !fixDistortedFaces( helper, tgtWires )) + return error("Invalid mesh generated"); + // --------------------------- // Check elements orientation // --------------------------- @@ -1405,6 +1412,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } } + cleaner.Release(); // not to remove mesh + return true; } -- 2.39.2