+
+ //================================================================================
+ /*!
+ * \brief Put quads to aCubeSide in the order of enum EBoxSides
+ */
+ //================================================================================
+
+ bool arrangeQuads( FaceQuadStructPtr quad[ 6 ], _FaceGrid aCubeSide[ 6 ], bool reverseBottom )
+ {
+ swap( aCubeSide[B_BOTTOM]._quad, quad[0] );
+ if ( reverseBottom )
+ swap( aCubeSide[B_BOTTOM]._quad->side[ Q_RIGHT],// direct the bottom normal inside cube
+ aCubeSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
+
+ aCubeSide[B_FRONT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_BOTTOM], quad );
+ aCubeSide[B_RIGHT]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_RIGHT ], quad );
+ aCubeSide[B_BACK ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_TOP ], quad );
+ aCubeSide[B_LEFT ]._quad = getQuadWithBottom( aCubeSide[B_BOTTOM]._quad->side[Q_LEFT ], quad );
+ if ( aCubeSide[B_FRONT ]._quad )
+ aCubeSide[B_TOP]._quad = getQuadWithBottom( aCubeSide[B_FRONT ]._quad->side[Q_TOP ], quad );
+
+ for ( int i = 1; i < 6; ++i )
+ if ( !aCubeSide[i]._quad )
+ return false;
+ return true;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Rearrange block sides according to StdMeshers_BlockRenumber hypothesis
+ */
+ //================================================================================
+
+ bool arrangeForRenumber( _FaceGrid blockSide[ 6 ],
+ TopoDS_Vertex& v000,
+ TopoDS_Vertex& v001 )
+ {
+ std::swap( blockSide[B_BOTTOM]._quad->side[ Q_RIGHT],// restore after arrangeQuads()
+ blockSide[B_BOTTOM]._quad->side[ Q_LEFT ] );
+
+ // find v000
+ TopTools_MapOfShape cornerVertices;
+ cornerVertices.Add( blockSide[B_BOTTOM]._quad->side[Q_BOTTOM].grid->LastVertex() );
+ cornerVertices.Add( blockSide[B_BOTTOM]._quad->side[Q_BOTTOM].grid->FirstVertex() );
+ cornerVertices.Add( blockSide[B_BOTTOM]._quad->side[Q_TOP ].grid->LastVertex() );
+ cornerVertices.Add( blockSide[B_BOTTOM]._quad->side[Q_TOP ].grid->FirstVertex() );
+ cornerVertices.Add( blockSide[B_TOP ]._quad->side[Q_BOTTOM].grid->FirstVertex() );
+ cornerVertices.Add( blockSide[B_TOP ]._quad->side[Q_BOTTOM].grid->LastVertex() );
+ cornerVertices.Add( blockSide[B_TOP ]._quad->side[Q_TOP ].grid->FirstVertex() );
+ cornerVertices.Add( blockSide[B_TOP ]._quad->side[Q_TOP ].grid->LastVertex() );
+
+ 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< StdMeshers_FaceSidePtr > edgesAtV000;
+ std::vector< gp_Vec > edgeDir;
+ std::vector< int > iParallel; // 0 - none, 1 - X, 2 - Y, 3 - Z
+ TopTools_MapOfShape lastVertices;
+ for ( int iQ = 0; iQ < 6; ++iQ )
+ {
+ FaceQuadStructPtr quad = blockSide[iQ]._quad;
+ for ( size_t iS = 0; iS < quad->side.size() && edgesAtV000.size() < 3; ++iS )
+ {
+ StdMeshers_FaceSidePtr edge = quad->side[iS];
+ TopoDS_Vertex v1 = edge->FirstVertex(), v2 = edge->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( edge );
+
+ 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 ( v001.IsSame( v2 ))
+ iParallel.back() = 3;
+ }
+ else
+ {
+ bool isStraight = true;
+ for ( int iE = 0; iE < edge->NbEdges() && isStraight; ++iE )
+ isStraight = SMESH_Algo::IsStraight( edge->Edge( iE ));
+
+ // 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
+ {
+ edgeDir.back() = gp_Vec( pf, edge->Value3d( reverse ? 0.99 : 0.01 ));
+ }
+ }
+ }
+ }
+ }
+ if ( std::accumulate( iParallel.begin(), iParallel.end(), 0 ) == 0 )
+ return false;
+
+ // find edge OZ and edge OX
+ StdMeshers_FaceSidePtr edgeOZ, edgeOX;
+ 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 ];
+ }
+ 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 ];
+ break;
+ }
+ }
+
+ if ( !edgeOZ || !edgeOX )
+ 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 ( int iQ = 0; iQ < 6; ++iQ )
+ {
+ FaceQuadStructPtr quad = blockSide[iQ]._quad;
+ bool hasV000 = false, hasV100 = false;
+ for ( size_t iS = 0; iS < quad->side.size(); ++iS )
+ {
+ StdMeshers_FaceSidePtr edge = quad->side[iS];
+ if ( edge->FirstVertex().IsSame( v000 ) || edge->LastVertex().IsSame( v000 ))
+ hasV000 = true;
+ if ( edge->FirstVertex().IsSame( v100 ) || edge->LastVertex().IsSame( v100 ))
+ hasV100 = true;
+ }
+ if ( hasV000 && !hasV100 )
+ {
+ // orient the left quad
+ for ( int i = 0; i < 4; ++i )
+ {
+ if ( quad->side[Q_BOTTOM].grid->Edge(0).IsSame( edgeOZ->Edge(0) ))
+ break;
+ quad->shift( 1, true );
+ }
+
+ FaceQuadStructPtr quads[ 6 ];
+ quads[0].swap( blockSide[iQ]._quad );
+ for ( int i = 1, j = 0; i < 6; ++i, ++j )
+ if ( blockSide[ j ]._quad )
+ quads[ i ].swap( blockSide[ j ]._quad );
+ else
+ --i;
+
+ return arrangeQuads( quads, blockSide, false/* true*/ );
+ }
+ }
+ return false;
+ }
+