+
+ //================================================================================
+ /*!
+ * \brief Find a face including two given nodes
+ */
+ //================================================================================
+
+ const SMDS_MeshElement* FindFaceByNodes( const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ TIDSortedElemSet avoidSet,
+ SMESH_ProxyMesh& mesh)
+ {
+ SMDS_ElemIteratorPtr faceIt = mesh.GetInverseElementIterator( n1, SMDSAbs_Face );
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* f = faceIt->next();
+ if ( !avoidSet.count( f ) && f->GetNodeIndex( n2 ) >= 0 )
+ return f;
+ }
+ return 0;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Check that a segment bounds a face belonging to smOfFaces
+ */
+ //================================================================================
+
+ bool IsSegmentOnSubMeshBoundary( const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const SMESHDS_SubMesh* smOfFaces,
+ SMESH_ProxyMesh& mesh)
+ {
+ TIDSortedElemSet avoidSet;
+ bool faceFound = false;
+
+ while ( const SMDS_MeshElement* f = FindFaceByNodes( n1, n2, avoidSet, mesh ))
+ {
+ if (( faceFound = smOfFaces->Contains( f )))
+ break;
+ avoidSet.insert( f );
+ }
+ return faceFound;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Rearrange block sides according to StdMeshers_BlockRenumber hypothesis
+ */
+ //================================================================================
+
+ bool arrangeForRenumber( list< _QuadFaceGrid >& blockSides,
+ const TopTools_MapOfShape& cornerVertices,
+ SMESH_Mesh* mesh,
+ TopoDS_Vertex& v000,
+ TopoDS_Vertex& v001 )
+ {
+ if ( v000.IsNull() )
+ {
+ // block CS is not defined;
+ // renumber only if the block has an edge parallel to an axis of global CS
+
+ v000 = StdMeshers_RenumberHelper::GetVertex000( cornerVertices );
+ }
+
+ Bnd_B3d bbox;
+ for ( auto it = cornerVertices.cbegin(); it != cornerVertices.cend(); ++it )
+ bbox.Add( BRep_Tool::Pnt( TopoDS::Vertex( *it )));
+ double tol = 1e-5 * Sqrt( bbox.SquareExtent() );
+
+ // get block edges starting at v000
+
+ std::vector< const _FaceSide* > edgesAtV000;
+ std::vector< gp_Vec > edgeDir;
+ std::vector< int > iParallel; // 0 - none, 1 - X, 2 - Y, 3 - Z
+ TopTools_MapOfShape lastVertices;
+ for ( _QuadFaceGrid & quad: blockSides )
+ {
+ for ( int iS = 0; iS < 4 && edgesAtV000.size() < 3; ++iS )
+ {
+ const _FaceSide* side = & quad.GetSide( iS );
+ TopoDS_Vertex v1 = side->FirstVertex(), v2 = side->LastVertex();
+ if (( v1.IsSame( v000 ) && !lastVertices.Contains( v2 )) ||
+ ( v2.IsSame( v000 ) && !lastVertices.Contains( v1 )))
+ {
+ bool reverse = v2.IsSame( v000 );
+ if ( reverse )
+ std::swap( v1, v2 );
+ lastVertices.Add( v2 );
+
+ edgesAtV000.push_back( side );
+
+ gp_Pnt pf = BRep_Tool::Pnt( v1 );
+ gp_Pnt pl = BRep_Tool::Pnt( v2 );
+ gp_Vec vec( pf, pl );
+ edgeDir.push_back( vec );
+
+ iParallel.push_back( 0 );
+ if ( !v001.IsNull() )
+ {
+ if ( quad.IsComplex() )
+ for ( _QuadFaceGrid::TChildIterator chIt = quad.GetChildren(); chIt.more(); )
+ {
+ const _QuadFaceGrid& child = chIt.next();
+ if ( child.GetSide( iS ).Contain( v001 ))
+ {
+ iParallel.back() = 3;
+ break;
+ }
+ }
+ else if ( side->Contain( v001 ))
+ iParallel.back() = 3;
+ }
+ else
+ {
+ bool isStraight = true;
+ std::list< TopoDS_Edge > edges;
+ for ( int iE = 0; true; ++iE )
+ {
+ TopoDS_Edge edge = side->Edge( iE );
+ if ( edge.IsNull() )
+ break;
+ edges.push_back( edge );
+ if ( isStraight )
+ isStraight = SMESH_Algo::IsStraight( edge );
+ }
+ // is parallel to a GCS axis?
+ if ( isStraight )
+ {
+ int nbDiff = (( Abs( vec.X() ) > tol ) +
+ ( Abs( vec.Y() ) > tol ) +
+ ( Abs( vec.Z() ) > tol ) );
+ if ( nbDiff == 1 )
+ iParallel.back() = ( Abs( vec.X() ) > tol ) ? 1 : ( Abs( vec.Y() ) > tol ) ? 2 : 3;
+ }
+ else
+ {
+ TopoDS_Face nullFace;
+ StdMeshers_FaceSide fSide( nullFace, edges, mesh, true, true );
+ edgeDir.back() = gp_Vec( pf, fSide.Value3d( reverse ? 0.99 : 0.01 ));
+ }
+ }
+ }
+ }
+ }
+ if ( std::accumulate( iParallel.begin(), iParallel.end(), 0 ) == 0 )
+ return false;
+
+ // find edge OZ and edge OX
+ const _FaceSide* edgeOZ = nullptr, *edgeOY = nullptr, *edgeOX = nullptr;
+ auto iZIt = std::find( iParallel.begin(), iParallel.end(), 3 );
+ if ( iZIt != iParallel.end() )
+ {
+ int i = std::distance( iParallel.begin(), iZIt );
+ edgeOZ = edgesAtV000[ i ];
+ int iE1 = SMESH_MesherHelper::WrapIndex( i + 1, edgesAtV000.size() );
+ int iE2 = SMESH_MesherHelper::WrapIndex( i + 2, edgesAtV000.size() );
+ if (( edgeDir[ iE1 ] ^ edgeDir[ iE2 ] ) * edgeDir[ i ] < 0 )
+ std::swap( iE1, iE2 );
+ edgeOX = edgesAtV000[ iE1 ];
+ edgeOY = edgesAtV000[ iE2 ];
+ }
+ else
+ {
+ for ( size_t i = 0; i < edgesAtV000.size(); ++i )
+ {
+ if ( !iParallel[ i ] )
+ continue;
+ int iE1 = SMESH_MesherHelper::WrapIndex( i + 1, edgesAtV000.size() );
+ int iE2 = SMESH_MesherHelper::WrapIndex( i + 2, edgesAtV000.size() );
+ if (( edgeDir[ iE1 ] ^ edgeDir[ iE2 ] ) * edgeDir[ i ] < 0 )
+ std::swap( iE1, iE2 );
+ edgeOZ = edgesAtV000[ iParallel[i] == 1 ? iE2 : iE1 ];
+ edgeOX = edgesAtV000[ iParallel[i] == 1 ? i : iE1 ];
+ edgeOY = edgesAtV000[ iParallel[i] == 1 ? iE1 : i ];
+ break;
+ }
+ }
+
+ if ( !edgeOZ || !edgeOX || !edgeOY )
+ return false;
+
+ TopoDS_Vertex v100 = edgeOX->LastVertex();
+ if ( v100.IsSame( v000 ))
+ v100 = edgeOX->FirstVertex();
+
+ // Find the left quad, one including v000 but not v100
+
+ for ( auto quad = blockSides.begin(); quad != blockSides.end(); ++quad )
+ {
+ if ( quad->Contain( v000 ) && !quad->Contain( v100 )) // it's a left quad
+ {
+ if ( quad != blockSides.begin() )
+ blockSides.splice( blockSides.begin(), blockSides, quad );
+ blockSides.front().SetBottomSide( *edgeOZ ); // edgeOY
+
+ return true;
+ }
+ }
+ return false;
+ }
+