From 52d825495306f72048c8754aa5c86c6a390f8262 Mon Sep 17 00:00:00 2001 From: eap Date: Thu, 13 Nov 2014 18:56:42 +0300 Subject: [PATCH 1/1] 22806: EDF SMESH: Regression: Prism_3D error Fix selection of the bottom; use block approach on simple shapes if swepper detects high bnd error --- src/SMESH/SMESH_MesherHelper.cxx | 2 +- src/StdMeshers/StdMeshers_Prism_3D.cxx | 119 ++++++++++++++++++------- src/StdMeshers/StdMeshers_Prism_3D.hxx | 8 +- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index eac668694..329c17e62 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -2464,7 +2464,7 @@ namespace //======================================================================= //function : IsStructured -//purpose : Return true if 2D mesh on FACE is structured +//purpose : Return true if 2D mesh on FACE is a structured rectangle //======================================================================= bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 8681b78d9..a95516934 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -661,12 +661,14 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh Prism_3D::TPrismTopo prism; myPropagChains = 0; + bool selectBottom = meshedFaces.empty(); if ( nbSolids == 1 ) { + TopoDS_Shape solid = TopExp_Explorer( theShape, TopAbs_SOLID ).Current(); if ( !meshedFaces.empty() ) prism.myBottom = meshedFaces.front(); - return ( initPrism( prism, TopExp_Explorer( theShape, TopAbs_SOLID ).Current() ) && + return ( initPrism( prism, solid, selectBottom ) && compute( prism )); } @@ -689,7 +691,6 @@ 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 ) { @@ -1105,7 +1106,9 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // Assure the bottom is meshed SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); - if ( ! NSProjUtils::MakeComputed( botSM )) + if (( botSM->IsEmpty() ) && + ( ! botSM->GetAlgo() || + ! _gen->Compute( *botSM->GetFather(), botSM->GetSubShape(), /*shapeOnly=*/true ))) return error( COMPERR_BAD_INPUT_MESH, TCom( "No mesher defined to compute the face #") << shapeID( thePrism.myBottom )); @@ -1157,6 +1160,7 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // use transformation (issue 0020680, IPAL0052499) StdMeshers_Sweeper sweeper; double tol; + bool allowHighBndError; if ( !myUseBlock ) { @@ -1178,9 +1182,10 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) sweeper.myIntColumns.push_back( & bot_column->second ); tol = getSweepTolerance( thePrism ); + allowHighBndError = !isSimpleBottom( thePrism ); } - if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol )) + if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol, allowHighBndError )) { } else // use block approach @@ -2297,6 +2302,44 @@ double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePr return 0.1 * Sqrt ( minDist ); } +//======================================================================= +//function : isSimpleQuad +//purpose : check if the bottom FACE is meshable with nice qudrangles, +// if so the block aproach can work rather fast. +// This is a temporary mean caused by problems in StdMeshers_Sweeper +//======================================================================= + +bool StdMeshers_Prism_3D::isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ) +{ + // analyse angles between edges + double nbConcaveAng = 0, nbConvexAng = 0; + TopoDS_Face reverseBottom = TopoDS::Face( thePrism.myBottom.Reversed() ); // see initPrism() + TopoDS_Vertex commonV; + const list< TopoDS_Edge >& botEdges = thePrism.myBottomEdges; + list< TopoDS_Edge >::const_iterator edge = botEdges.begin(); + for ( ; edge != botEdges.end(); ++edge ) + { + if ( SMESH_Algo::isDegenerated( *edge )) + return false; + TopoDS_Edge e1 = *edge++; + TopoDS_Edge e2 = ( edge == botEdges.end() ? botEdges.front() : *edge ); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + { + e2 = botEdges.front(); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + break; + } + double angle = myHelper->GetAngle( e1, e2, reverseBottom, commonV ); + if ( angle < -5 * M_PI/180 ) + if ( ++nbConcaveAng > 1 ) + return false; + if ( angle > 85 * M_PI/180 ) + if ( ++nbConvexAng > 4 ) + return false; + } + return true; +} + //======================================================================= //function : project2dMesh //purpose : Project mesh faces from a source FACE of one prism (theSrcFace) @@ -2835,17 +2878,18 @@ void StdMeshers_PrismAsBlock::Clear() //======================================================================= bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, - const TopoDS_Shape& shape3D, + const TopoDS_Shape& theShape3D, const bool selectBottom) { - myHelper->SetSubShape( shape3D ); + myHelper->SetSubShape( theShape3D ); - SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); + SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( theShape3D ); if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D")); // detect not-quad FACE sub-meshes of the 3D SHAPE list< SMESH_subMesh* > notQuadGeomSubMesh; list< SMESH_subMesh* > notQuadElemSubMesh; + list< SMESH_subMesh* > meshedSubMesh; int nbFaces = 0; // SMESH_subMesh* anyFaceSM = 0; @@ -2867,10 +2911,14 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, if ( nbWires != 1 || nbEdgesInWires.front() != 4 ) notQuadGeomSubMesh.push_back( sm ); - // look for not quadrangle mesh elements - if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) - if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + // look for a not structured sub-mesh + if ( !sm->IsEmpty() ) + { + meshedSubMesh.push_back( sm ); + if ( !myHelper->IsSameElemGeometry( sm->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) || + !myHelper->IsStructured ( sm )) notQuadElemSubMesh.push_back( sm ); + } } int nbNotQuadMeshed = notQuadElemSubMesh.size(); @@ -2953,25 +3001,32 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, } if ( !botSM ) // find a proper bottom { - // composite walls or not prism shape - for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() ) + bool savedSetErrorToSM = mySetErrorToSM; + mySetErrorToSM = false; // ingore errors in initPrism() + + // search among meshed FACEs + list< SMESH_subMesh* >::iterator sm = meshedSubMesh.begin(); + for ( ; !botSM && sm != meshedSubMesh.end(); ++sm ) + { + thePrism.Clear(); + botSM = *sm; + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; + } + // search among all FACEs + for ( TopExp_Explorer f( theShape3D, TopAbs_FACE ); !botSM && f.More(); f.Next() ) { int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false); - if ( nbFaces >= minNbFaces) - { - thePrism.Clear(); - thePrism.myBottom = TopoDS::Face( f.Current() ); - 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; - } - } + if ( nbFaces < minNbFaces) continue; + thePrism.Clear(); + thePrism.myBottom = TopoDS::Face( f.Current() ); + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; } - return toSM( error( COMPERR_BAD_SHAPE )); + mySetErrorToSM = savedSetErrorToSM; + return botSM ? true : toSM( error( COMPERR_BAD_SHAPE )); } // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) @@ -2990,11 +3045,11 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, } } - thePrism.myShape3D = shape3D; + thePrism.myShape3D = theShape3D; if ( thePrism.myBottom.IsNull() ) thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); - thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( shape3D, thePrism.myBottom )); - thePrism.myTop. Orientation( myHelper->GetSubShapeOri( shape3D, thePrism.myTop )); + thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myBottom )); + thePrism.myTop. Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myTop )); // Get ordered bottom edges TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE @@ -4491,7 +4546,8 @@ void StdMeshers_Sweeper::applyBoundaryError(const vector< gp_XYZ >& bndPoints, //================================================================================ bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper, - const double tol) + const double tol, + const bool allowHighBndError) { const size_t zSize = myBndColumns[0]->size(); const size_t zSrc = 0, zTgt = zSize-1; @@ -4610,6 +4666,9 @@ bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper, bndErrorIsSmall = ( sumError < tol ); } + if ( !bndErrorIsSmall && !allowHighBndError ) + return false; + // compute final points on the central layer std::vector< double > int2BndDist( myBndColumns.size() ); // work array of applyBoundaryError() double r = zS / ( zSize - 1.); diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx index 5d99375a9..546bf4950 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.hxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -412,7 +412,8 @@ struct StdMeshers_Sweeper std::vector< TNodeColumn* > myIntColumns; // internal nodes bool ComputeNodes( SMESH_MesherHelper& helper, - const double tol ); + const double tol, + const bool allowHighBndError ); private: @@ -529,6 +530,11 @@ public: */ double getSweepTolerance( const Prism_3D::TPrismTopo& thePrism ); + /*! + * \brief Defines if it's safe to use the block approach + */ + bool isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ); + /*! * \brief Project mesh faces from a source FACE of one prism to * a source FACE of another prism -- 2.30.2