X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Prism_3D.cxx;h=2a8baf1ec8e0f0ffa180ff4ccf7e5c3db46c3d9f;hp=9dde41365e3a12a664c5409d757d41c01b39da36;hb=88ff35ddd4a4442397bc5f6ba893aaf9c51b1856;hpb=80637e48ef0a19bb89acdf00c98959ab08b5dcc8 diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 9dde41365..2a8baf1ec 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2021 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 @@ -33,6 +33,7 @@ #include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" #include "SMESH_HypoFilter.hxx" +#include "SMESH_MeshEditor.hxx" #include "SMESH_MesherHelper.hxx" #include "StdMeshers_FaceSide.hxx" #include "StdMeshers_ProjectionSource1D.hxx" @@ -88,23 +89,50 @@ 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); + _meshDS = new SMESHDS_Mesh( _id, true ); + } + }; //======================================================================= /*! * \brief Quadrangle algorithm */ - struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D + class TQuadrangleAlgo : public StdMeshers_Quadrangle_2D { - TQuadrangleAlgo(int studyId, SMESH_Gen* gen) - : StdMeshers_Quadrangle_2D( gen->GetANewId(), studyId, gen) + 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 { - static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetStudyId(), - fatherAlgo->GetGen() ); + 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 && algo->myProxyMesh && algo->myProxyMesh->GetMesh() != helper->GetMesh() ) @@ -118,7 +146,124 @@ namespace { return algo; } + + //================================================================================ + // Clear collected data + void reset() + { + StdMeshers_Quadrangle_2D::myQuadList.clear(); + StdMeshers_Quadrangle_2D::myHelper = nullptr; + StdMeshers_Quadrangle_2D::myProxyMesh.reset(); + myFace2QuadMap.Clear(); + } + + //================================================================================ + /*! + * \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 @@ -127,16 +272,15 @@ namespace { { StdMeshers_ProjectionSource1D myHyp; - TProjction1dAlgo(int studyId, SMESH_Gen* gen) - : StdMeshers_Projection_1D( gen->GetANewId(), studyId, gen), - myHyp( gen->GetANewId(), studyId, gen) + TProjction1dAlgo(SMESH_Gen* gen) + : StdMeshers_Projection_1D( gen->GetANewId(), gen), + myHyp( gen->GetANewId(), gen) { StdMeshers_Projection_1D::_sourceHypo = & myHyp; } static TProjction1dAlgo* instance( SMESH_Algo* fatherAlgo ) { - static TProjction1dAlgo* algo = new TProjction1dAlgo( fatherAlgo->GetStudyId(), - fatherAlgo->GetGen() ); + static TProjction1dAlgo* algo = new TProjction1dAlgo( fatherAlgo->GetGen() ); return algo; } }; @@ -148,16 +292,15 @@ namespace { { StdMeshers_ProjectionSource2D myHyp; - TProjction2dAlgo(int studyId, SMESH_Gen* gen) - : StdMeshers_Projection_1D2D( gen->GetANewId(), studyId, gen), - myHyp( gen->GetANewId(), studyId, gen) + TProjction2dAlgo(SMESH_Gen* gen) + : StdMeshers_Projection_1D2D( gen->GetANewId(), gen), + myHyp( gen->GetANewId(), gen) { StdMeshers_Projection_2D::_sourceHypo = & myHyp; } static TProjction2dAlgo* instance( SMESH_Algo* fatherAlgo ) { - static TProjction2dAlgo* algo = new TProjction2dAlgo( fatherAlgo->GetStudyId(), - fatherAlgo->GetGen() ); + static TProjction2dAlgo* algo = new TProjction2dAlgo( fatherAlgo->GetGen() ); return algo; } const NSProjUtils::TNodeNodeMap& GetNodesMap() @@ -402,7 +545,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(); @@ -411,7 +554,7 @@ namespace { { SMESH_subMesh* faceSm = *smIt; SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS(); - int nbQuads = faceSmDS ? faceSmDS->NbElements() : 0; + smIdType nbQuads = faceSmDS ? faceSmDS->NbElements() : 0; bool toRemove; if ( nbQuads > 0 ) toRemove = helper->IsStructured( faceSm ); @@ -452,13 +595,13 @@ namespace { //================================================================================ int countNbSides( const Prism_3D::TPrismTopo & thePrism, - vector & nbUnitePerEdge, + vector & /*nbUnitePerEdge*/, vector< double > & edgeLength) { int nbEdges = thePrism.myNbEdgesInWires.front(); // nb outer edges int nbSides = nbEdges; - + list< TopoDS_Edge >::const_iterator edgeIt = thePrism.myBottomEdges.begin(); std::advance( edgeIt, nbEdges-1 ); TopoDS_Edge prevE = *edgeIt; @@ -526,10 +669,26 @@ namespace { // isPrevStraight = isCurStraight; // iPrev = iE; // } - + 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,17 +718,20 @@ namespace { cout << "mesh.AddNode( " << p[i].X() << ", "<< p[i].Y() << ", "<< p[i].Z() << ") # " << i <<" " ; SMESH_Block::DumpShapeID( i, cout ) << endl; } +#else + (void)p; // unused in release mode #endif } + } // namespace //======================================================================= //function : StdMeshers_Prism_3D -//purpose : +//purpose : //======================================================================= -StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen) - :SMESH_3D_Algo(hypId, studyId, gen) +StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, gen) { _name = "Prism_3D"; _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type @@ -597,11 +759,11 @@ StdMeshers_Prism_3D::~StdMeshers_Prism_3D() //======================================================================= //function : CheckHypothesis -//purpose : +//purpose : //======================================================================= -bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, +bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& /*aMesh*/, + const TopoDS_Shape& /*aShape*/, SMESH_Hypothesis::Hypothesis_Status& aStatus) { // no hypothesis @@ -619,6 +781,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh SMESH_MesherHelper helper( theMesh ); myHelper = &helper; myPrevBottomSM = 0; + TQuadrangleAlgo::Cleaner quadCleaner( TQuadrangleAlgo::instance( this )); int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false ); if ( nbSolids < 1 ) @@ -630,7 +793,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 )); @@ -689,6 +851,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh } TopTools_MapOfShape meshedSolids; + NCollection_DataMap< TopoDS_Shape, SMESH_subMesh* > meshedFace2AlgoSM; list< Prism_3D::TPrismTopo > meshedPrism; list< TopoDS_Face > suspectSourceFaces; TopTools_ListIteratorOfListOfShape solidIt; @@ -712,14 +875,22 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { prism.Clear(); prism.myBottom = face; + if ( meshedFace2AlgoSM.IsBound( face )) + prism.myAlgoSM = meshedFace2AlgoSM.Find( face ); if ( !initPrism( prism, solid, selectBottom ) || !compute( prism )) 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 ); + if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() ) + { + meshedFace2AlgoSM.Bind( prism.myTop, prism.myAlgoSM ); + meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM ); + } } else { @@ -754,9 +925,18 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh solidList.Remove( solidIt ); continue; // already computed prism } - if ( myHelper->IsBlock( solid )) { - solidIt.Next(); - continue; // too trivial + if ( myHelper->IsBlock( solid )) + { + bool isStructBase = true; + if ( prismIt->myAlgoSM ) + isStructBase = ( myHelper->IsSameElemGeometry( prismIt->myAlgoSM->GetSubMeshDS(), + SMDSGeom_QUADRANGLE ) && + myHelper->IsStructured(prismIt->myAlgoSM )); + if ( isStructBase ) + { + solidIt.Next(); + continue; // too trivial + } } // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0); @@ -775,27 +955,41 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh } prism.Clear(); prism.myBottom = candidateF; + prism.myAlgoSM = prismIt->myAlgoSM; mySetErrorToSM = false; if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) && myHelper ->IsSubShape( candidateF, solid ) && !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() && initPrism( prism, solid, /*selectBottom=*/false ) && !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() && - !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() && - project2dMesh( sourceF, prism.myBottom )) + !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() ) { - mySetErrorToSM = true; - if ( !compute( prism )) - return false; - SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop ); - if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + if ( project2dMesh( sourceF, prism.myBottom )) + { + mySetErrorToSM = true; + if ( !compute( prism )) + return false; + SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop ); + if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + { + meshedFaces.push_front( prism.myTop ); + meshedFaces.push_front( prism.myBottom ); + selectBottom = false; + if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() ) + { + meshedFace2AlgoSM.Bind( prism.myTop, prism.myAlgoSM ); + meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM ); + } + } + meshedPrism.push_back( prism ); + meshedSolids.Add( solid ); + } + else { - meshedFaces.push_front( prism.myTop ); - meshedFaces.push_front( prism.myBottom ); - selectBottom = false; + suspectSourceFaces.push_back( prism.myBottom ); + if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() ) + meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM ); } - meshedPrism.push_back( prism ); - meshedSolids.Add( solid ); } InitComputeError(); } @@ -831,7 +1025,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); if ( !faceSM->IsEmpty() ) { - int nbFaces = faceSM->GetSubMeshDS()->NbElements(); + smIdType nbFaces = faceSM->GetSubMeshDS()->NbElements(); if ( prevNbFaces < nbFaces ) { if ( !meshedFaces.empty() ) meshedFaces.pop_back(); @@ -848,7 +1042,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh allSubMeComputed = smIt->next()->IsMeshComputed(); if ( allSubMeComputed ) { - faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH ); if ( !faceSM->IsEmpty() ) { meshedFaces.push_front( face ); // higher priority selectBottom = true; @@ -921,10 +1115,10 @@ 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; + TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces; TopExp::MapShapesAndAncestors( thePrism.myShape3D, TopAbs_EDGE, TopAbs_FACE, edgeToFaces ); @@ -959,7 +1153,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, if ( !quadList.back() ) return toSM( error(TCom("Side face #") << shapeID( face ) << " not meshable with quadrangles")); - bool isCompositeBase = ! setBottomEdge( *edge, quadList.back(), face ); + bool isCompositeBase = ! setBottomEdge( *edge, quadList.back(), face ); // -> orient CCW if ( isCompositeBase ) { // it's OK if all EDGEs of the bottom side belongs to the bottom FACE @@ -1170,6 +1364,11 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) if ( !assocOrProjBottom2Top( bottomToTopTrsf, thePrism ) ) // it also fills myBotToColumnMap return false; + // If all "vertical" EDGEs are straight, then all nodes of an internal node column + // are located on a line connecting the top node and the bottom node. + bool isStrightColunm = allVerticalEdgesStraight( thePrism ); + if ( isStrightColunm ) + myUseBlock = false; // Create nodes inside the block @@ -1208,9 +1407,6 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) myHelper->SetElementsOnShape( true ); - // If all "vertical" EDGEs are straight, then all nodes of an internal node column - // are located on a line connecting the top node and the bottom node. - bool isStrightColunm = allVerticalEdgesStraight( thePrism ); if ( !isStrightColunm ) { double tol = getSweepTolerance( thePrism ); @@ -1400,8 +1596,9 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism) { // find any applicable algorithm assigned to any FACE of the main shape std::vector< TopoDS_Shape > faces; - if ( myPrevBottomSM && - myPrevBottomSM->GetAlgo()->IsApplicableToShape( thePrism.myBottom, /*all=*/false )) + if ( thePrism.myAlgoSM && thePrism.myAlgoSM->GetAlgo() ) + faces.push_back( thePrism.myAlgoSM->GetSubShape() ); + if ( myPrevBottomSM && myPrevBottomSM->GetAlgo() ) faces.push_back( myPrevBottomSM->GetSubShape() ); TopExp_Explorer faceIt( mesh->GetShapeToMesh(), TopAbs_FACE ); @@ -1426,7 +1623,7 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism) while ( smIt->more() && subOK ) { SMESH_subMesh* sub = smIt->next(); - sub->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + sub->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH ); subOK = sub->IsMeshComputed(); } if ( !subOK ) @@ -1434,23 +1631,31 @@ bool StdMeshers_Prism_3D::computeBase(const Prism_3D::TPrismTopo& thePrism) } try { OCC_CATCH_SIGNALS; + + Hypothesis_Status status; + algo->CheckHypothesis( *mesh, faces[i], status ); algo->InitComputeError(); - algo->Compute( *mesh, botSM->GetSubShape() ); + if ( algo->Compute( *mesh, botSM->GetSubShape() )) + { + myPrevBottomSM = thePrism.myAlgoSM = mesh->GetSubMesh( faces[i] ); + break; + } } catch (...) { } } } } + else + { + myPrevBottomSM = thePrism.myAlgoSM = botSM; + } if ( botSM->IsEmpty() ) return error( COMPERR_BAD_INPUT_MESH, TCom( "No mesher defined to compute the base face #") << shapeID( thePrism.myBottom )); - if ( botSM->GetAlgo() ) - myPrevBottomSM = botSM; - return true; } @@ -1465,8 +1670,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 )); @@ -1544,7 +1749,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) } // assure that all the source (left) EDGEs are meshed - int nbSrcSegments = 0; + smIdType nbSrcSegments = 0; for ( int i = 0; i < lftSide->NbEdges(); ++i ) { if ( isArtificialQuad ) @@ -1636,6 +1841,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) mesh->GetSubMesh( v )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, meshDS ); newNodes[ is2ndV ? newNodes.size()-1 : 0 ] = (SMDS_MeshNode*) n; + if ( !n ) + return toSM( error( TCom("No node on vertex #") << meshDS->ShapeToIndex( v ))); } // compute nodes on target EDGEs @@ -1653,7 +1860,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) for ( size_t iN = 1; iN < srcNodeStr.size(); ++iN ) // add segments { // find an EDGE to set a new segment - std::pair id2type = + std::pair id2type = myHelper->GetMediumPos( newNodes[ iN-1 ], newNodes[ iN ] ); if ( id2type.second != TopAbs_EDGE ) { @@ -1673,7 +1880,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) { SMESH_MeshEditor::TListOfListOfNodes lln( 1, list< const SMDS_MeshNode* >() ); lln.back().push_back ( vn ); - lln.back().push_front( newNodes[ iN-isPrev ] ); // to keep + lln.back().push_front( newNodes[ iN-isPrev ] ); // to keep SMESH_MeshEditor( mesh ).MergeNodes( lln ); } } @@ -1798,9 +2005,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) if ( myHelper->GetIsQuadratic() ) { // fill myHelper with medium nodes built by quadAlgo - SMDS_ElemIteratorPtr fIt = fSM->GetSubMeshDS()->GetElements(); - while ( fIt->more() ) - myHelper->AddTLinks( dynamic_cast( fIt->next() )); + for ( SMDS_ElemIteratorPtr fIt = fSM->GetSubMeshDS()->GetElements(); fIt->more(); ) + myHelper->AddTLinks( SMDS_Mesh::DownCast( fIt->next() )); } } } @@ -1940,9 +2146,9 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, if( anIt==aResMap.end() ) return toSM( error( "Submesh can not be evaluated")); - std::vector aVec = (*anIt).second; - int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); - int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + std::vector aVec = (*anIt).second; + smIdType nbtri = std::max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + smIdType nbqua = std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); if( nbtri==0 && nbqua>0 ) { NbQFs++; } @@ -1952,7 +2158,7 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, } if(NbQFs<4) { - std::vector aResVec(SMDSEntity_Last); + std::vector aResVec(SMDSEntity_Last); for(int i=SMDSEntity_Node; i set 1 faces as base // find number of 1d elems for base face - int nb1d = 0; + smIdType nb1d = 0; TopTools_MapOfShape Edges1; for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) { Edges1.Add(exp.Current()); @@ -1970,8 +2176,8 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, if( sm ) { MapShapeNbElemsItr anIt = aResMap.find(sm); if( anIt == aResMap.end() ) continue; - std::vector aVec = (*anIt).second; - nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); + std::vector aVec = (*anIt).second; + nb1d += std::max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); } } // find face opposite to base face @@ -1991,25 +2197,25 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, } } // find number of 2d elems on side faces - int nb2d = 0; + smIdType nb2d = 0; for(i=1; i<=6; i++) { if( i==OppNum || i==NumBase ) continue; MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] ); if( anIt == aResMap.end() ) continue; - std::vector aVec = (*anIt).second; - nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + std::vector aVec = (*anIt).second; + nb2d += std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); } - + MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] ); - std::vector aVec = (*anIt).second; + std::vector aVec = (*anIt).second; bool IsQuadratic = (aVec[SMDSEntity_Quad_Triangle]>aVec[SMDSEntity_Triangle]) || (aVec[SMDSEntity_Quad_Quadrangle]>aVec[SMDSEntity_Quadrangle]); - int nb2d_face0_3 = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); - int nb2d_face0_4 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); - int nb0d_face0 = aVec[SMDSEntity_Node]; - int nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2; + smIdType nb2d_face0_3 = std::max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); + smIdType nb2d_face0_4 = std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); + smIdType nb0d_face0 = aVec[SMDSEntity_Node]; + smIdType nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2; - std::vector aResVec(SMDSEntity_Last); + std::vector aResVec(SMDSEntity_Last); for(int i=SMDSEntity_Node; iNbEdges(); ++iE ) { + // sides are CWW oriented NSProjUtils::InsertAssociation( botSide->Edge( iE ), topSide->Edge( iE ), shape2ShapeMap ); - NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )), - myHelper->IthVertex( 0, topSide->Edge( iE )), + NSProjUtils::InsertAssociation( botSide->FirstVertex( iE ), + topSide->LastVertex ( iE ), shape2ShapeMap ); } } @@ -2277,7 +2484,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf // Fill myBotToColumnMap - int zSize = myBlock.VerticalSize(); + size_t zSize = myBlock.VerticalSize(); TNodeNodeMap::const_iterator bN_tN = n2nMapPtr->begin(); for ( ; bN_tN != n2nMapPtr->end(); ++bN_tN ) { @@ -2312,7 +2519,7 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom { return true; } - NSProjUtils::TNodeNodeMap& n2nMap = + NSProjUtils::TNodeNodeMap& n2nMap = (NSProjUtils::TNodeNodeMap&) TProjction2dAlgo::instance( this )->GetNodesMap(); n2nMap.clear(); @@ -2349,7 +2556,7 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom // Fill myBotToColumnMap - int zSize = myBlock.VerticalSize(); + size_t zSize = myBlock.VerticalSize(); Prism_3D::TNode prevTNode; SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes(); while ( nIt->more() ) @@ -2397,7 +2604,7 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottom meshDS->MoveNode( topNode, distXYZ[1], distXYZ[2], distXYZ[3] ); // transform can be inaccurate } // create node column - TNode2ColumnMap::iterator bN_col = + TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); @@ -2545,7 +2752,7 @@ double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePr for ( int iN = 0; iN < nbNodes; ++iN ) nodes[ iN ] = nIt->next(); nodes.back() = nodes[0]; - + // loop on links double dist2; for ( int iN = 0; iN < nbNodes; ++iN ) @@ -2591,7 +2798,7 @@ double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePr //======================================================================= //function : isSimpleQuad //purpose : check if the bottom FACE is meshable with nice quadrangles, -// if so the block aproach can work rather fast. +// if so the block approach can work rather fast. // This is a temporary mean caused by problems in StdMeshers_Sweeper //======================================================================= @@ -2675,6 +2882,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 ); @@ -2706,7 +2916,7 @@ bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, */ //================================================================================ -bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ) +bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int /*z*/ ) { // find base and top edges of the face enum { BASE = 0, TOP, LEFT, RIGHT }; @@ -2772,22 +2982,53 @@ 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 + // PrismSide contains all FACEs linking a bottom EDGE with a top one. + struct PrismSide { TopoDS_Face _face; // a currently treated upper FACE TopTools_IndexedMapOfShape *_faces; // all FACEs (pointer because of a private copy constructor) @@ -2799,8 +3040,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; @@ -2811,14 +3052,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; } @@ -2828,20 +3088,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, @@ -2857,11 +3136,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 ); @@ -2869,6 +3147,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(); @@ -2884,40 +3163,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; @@ -2925,7 +3215,7 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() } return edges.size(); } - + //-------------------------------------------------------------------------------- /*! * \brief Return number of faces sharing given edges @@ -3050,11 +3340,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 ]; @@ -3066,19 +3356,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; @@ -3146,7 +3449,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(); @@ -3176,7 +3479,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 ) { @@ -3187,12 +3490,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 @@ -3239,6 +3550,7 @@ namespace Prism_3D myBottomEdges.clear(); myNbEdgesInWires.clear(); myWallQuads.clear(); + myAlgoSM = nullptr; } //================================================================================ @@ -3538,7 +3850,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, SMESH_Block::init(); myShapeIDMap.Clear(); myShapeIndex2ColumnMap.clear(); - + int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz @@ -3599,7 +3911,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face )); } - if ( !faceColumns.empty() && (int)faceColumns.begin()->second.size() != VerticalSize() ) + if ( !faceColumns.empty() && faceColumns.begin()->second.size() != VerticalSize() ) return error(COMPERR_BAD_INPUT_MESH, "Different 'vertical' discretization"); // edge columns @@ -3915,7 +4227,7 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & const Prism_3D::TPrismTopo& prism) const { const bool itTopMeshed = !SubMesh( ID_BOT_FACE )->IsEmpty(); - const int zSize = VerticalSize(); + const size_t zSize = VerticalSize(); if ( zSize < 3 && !itTopMeshed ) return true; trsf.resize( zSize - 1 ); @@ -3962,7 +4274,7 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & gp_Ax3 cs0 = getLayerCoordSys(0, columns, xCol ); //double dist0 = cs0.Location().Distance( gpXYZ( (*columns[0])[0])); toCs0.SetTransformation( cs0 ); - for ( int z = 1; z < zSize; ++z ) + for ( size_t z = 1; z < zSize; ++z ) { gp_Ax3 csZ = getLayerCoordSys(z, columns, xCol ); //double distZ = csZ.Location().Distance( gpXYZ( (*columns[0])[z])); @@ -3981,7 +4293,7 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & if ( p0.SquareDistance( pz ) > tol2 ) { t = gp_Trsf(); - return ( z == zSize - 1 ); // OK if fails only botton->top trsf + return ( z == zSize - 1 ); // OK if fails only bottom->top trsf } } } @@ -3990,12 +4302,12 @@ 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 coinside with in-block forward orientation + * \retval bool - true if orientation coincide with in-block forward orientation */ //================================================================================ @@ -4066,7 +4378,9 @@ void StdMeshers_PrismAsBlock::faceGridToPythonDump(const SMESH_Block::TShapeID f << n << ", " << n+1 << ", " << n+nb+2 << ", " << n+nb+1 << "]) " << endl; } - +#else + (void)face; // unused in release mode + (void)nb; // unused in release mode #endif } @@ -4218,8 +4532,8 @@ Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::VertiCurve(const bool isMax //================================================================================ /*! * \brief Return geometry of the top or bottom curve - * \param isTop - - * \retval Adaptor3d_Curve* - + * \param isTop - + * \retval Adaptor3d_Curve* - */ //================================================================================ @@ -4475,7 +4789,7 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, meshDS->IndexToShape( notFaceID2 ), *myHelper.GetMesh(), TopAbs_FACE ); - if ( face.IsNull() ) + if ( face.IsNull() ) throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() face.IsNull()"); int faceID = meshDS->ShapeToIndex( face ); me->mySurface = me->myShapeID2Surf[ faceID ]; @@ -4541,7 +4855,7 @@ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const column = & ( myParamToColumnMap->rbegin()->second ); else column = & ( myParamToColumnMap->begin()->second ); - if ( column->size() > 0 ) + if ( column->size() > 1 ) edge = myHelper.GetSubShapeByNode( (*column)[ 1 ], meshDS ); if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX ) node = column->front(); @@ -4605,7 +4919,7 @@ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) if ( v1.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap); } - + // from V1 column SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V1_EDGE ], vertIdVec); GetColumns(1, col1, col2 ); @@ -4653,7 +4967,7 @@ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) // if ( edgeID = edgeIdVec[ _v1 ]) edgeID = edgeIdVec[ _v0 ]; // else edgeID = edgeIdVec[ _v1 ]; // SMESH_Block::Insert( sideEdge, edgeID, shapeMap); - + // // top edge // TopoDS_Edge topEdge = GetEdge( TOP_EDGE ); // SMESH_Block::Insert( topEdge, edgeIdVec[ _u1 ], shapeMap); @@ -4686,12 +5000,14 @@ void StdMeshers_PrismAsBlock::TSideFace::dumpNodes(int nbNodes) const TVerticalEdgeAdaptor* vSide1 = (TVerticalEdgeAdaptor*) VertiCurve(1); cout << "Verti side 1: "; vSide1->dumpNodes(nbNodes); cout << endl; delete hSize0; delete hSize1; delete vSide0; delete vSide1; +#else + (void)nbNodes; // unused in release mode #endif } //================================================================================ /*! - * \brief Creates TVerticalEdgeAdaptor + * \brief Creates TVerticalEdgeAdaptor * \param columnsMap - node column map * \param parameter - normalized parameter */ @@ -4732,6 +5048,8 @@ void StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::dumpNodes(int nbNodes) const cout << (*myNodeColumn)[i]->GetID() << " "; if ( nbNodes < (int) myNodeColumn->size() ) cout << myNodeColumn->back()->GetID(); +#else + (void)nbNodes; // unused in release mode #endif } @@ -4766,7 +5084,7 @@ void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) con TParam2ColumnIt col, col2; TParam2ColumnMap* u2cols = side->GetColumns(); side->GetColumns( u , col, col2 ); - + int j, i = myV ? mySide->ColumnHeight()-1 : 0; const SMDS_MeshNode* n = 0; @@ -4790,12 +5108,14 @@ void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) con side->GetColumns( u , col, col2 ); if ( n != col->second[ i ] ) cout << col->second[ i ]->GetID(); +#else + (void)nbNodes; // unused in release mode #endif } //================================================================================ /*! - * \brief Costructor of TPCurveOnHorFaceAdaptor fills its map of + * \brief Constructor of TPCurveOnHorFaceAdaptor fills its map of * normalized parameter to node UV on a horizontal face * \param [in] sideFace - lateral prism side * \param [in] isTop - is \a horFace top or bottom of the prism @@ -4847,7 +5167,7 @@ TPCurveOnHorFaceAdaptor::TPCurveOnHorFaceAdaptor( const TSideFace* sideFace, } if ( !C2d.IsNull() ) { - double u = static_cast< const SMDS_EdgePosition* >( n->GetPosition() )->GetUParameter(); + double u = SMDS_EdgePositionPtr( n->GetPosition() )->GetUParameter(); if ( f <= u && u <= l ) { uv = C2d->Value( u ).XY(); @@ -5122,10 +5442,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 ) @@ -5295,7 +5615,7 @@ bool StdMeshers_Sweeper::ComputeNodesOnStraight() int botTriaNodes[3], topTriaNodes[3]; bool checkUV = true; - int nbInternalNodes = myIntColumns.size(); + size_t nbInternalNodes = myIntColumns.size(); myBotDelaunay->InitTraversal( nbInternalNodes ); while (( botNode = myBotDelaunay->NextNode( botBC, botTriaNodes ))) @@ -5364,15 +5684,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; @@ -5425,7 +5764,7 @@ bool StdMeshers_Sweeper::findDelaunayTriangles() TopBotTriangles tbTrias; bool checkUV = true; - int nbInternalNodes = myIntColumns.size(); + size_t nbInternalNodes = myIntColumns.size(); myTopBotTriangles.resize( nbInternalNodes ); myBotDelaunay->InitTraversal( nbInternalNodes );