+ if ( foundNbRows != expectedNbRows )
+ return false;
+ avoidSet.clear();
+ }
+ return ( theParam2ColumnMap.size() > 1 &&
+ theParam2ColumnMap.begin()->second.size() == prevNbRows + expectedNbRows );
+}
+
+namespace
+{
+ //================================================================================
+ /*!
+ * \brief Return true if a node is at a corner of a 2D structured mesh of FACE
+ */
+ //================================================================================
+
+ bool isCornerOfStructure( const SMDS_MeshNode* n,
+ const SMESHDS_SubMesh* faceSM,
+ SMESH_MesherHelper& faceAnalyser )
+ {
+ int nbFacesInSM = 0;
+ if ( n ) {
+ SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ nbFacesInSM += faceSM->Contains( fIt->next() );
+ }
+ if ( nbFacesInSM == 1 )
+ return true;
+
+ if ( nbFacesInSM == 2 && n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
+ {
+ return faceAnalyser.IsRealSeam( n->getshapeId() );
+ }
+ return false;
+ }
+}
+
+//=======================================================================
+//function : IsStructured
+//purpose : Return true if 2D mesh on FACE is structured
+//=======================================================================
+
+bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM )
+{
+ SMESHDS_SubMesh* fSM = faceSM->GetSubMeshDS();
+ if ( !fSM || fSM->NbElements() == 0 )
+ return false;
+
+ list< TopoDS_Edge > edges;
+ list< int > nbEdgesInWires;
+ int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSM->GetSubShape() ),
+ edges, nbEdgesInWires );
+ if ( nbWires != 1 || nbEdgesInWires.front() != 4 )
+ return false;
+
+ // algo: find corners of a structure and then analyze nb of faces and
+ // length of structure sides
+
+ SMESHDS_Mesh* meshDS = faceSM->GetFather()->GetMeshDS();
+ SMESH_MesherHelper faceAnalyser( *faceSM->GetFather() );
+ faceAnalyser.SetSubShape( faceSM->GetSubShape() );
+
+ // rotate edges to get the first node being at corner
+ // (in principle it's not necessary but so far none SALOME algo can make
+ // such a structured mesh that all corner nodes are not on VERTEXes)
+ bool isCorner = false;
+ int nbRemainEdges = nbEdgesInWires.front();
+ do {
+ TopoDS_Vertex V = IthVertex( 0, edges.front() );
+ isCorner = isCornerOfStructure( SMESH_Algo::VertexNode( V, meshDS ),
+ fSM, faceAnalyser);
+ if ( !isCorner ) {
+ edges.splice( edges.end(), edges, edges.begin() );
+ --nbRemainEdges;
+ }
+ }
+ while ( !isCorner && nbRemainEdges > 0 );
+
+ if ( !isCorner )
+ return false;
+
+ // get all nodes from EDGEs
+ list< const SMDS_MeshNode* > nodes;
+ list< TopoDS_Edge >::iterator edge = edges.begin();
+ for ( ; edge != edges.end(); ++edge )
+ {
+ map< double, const SMDS_MeshNode* > u2Nodes;
+ if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, *edge,
+ /*skipMedium=*/true, u2Nodes ))
+ return false;
+
+ list< const SMDS_MeshNode* > edgeNodes;
+ map< double, const SMDS_MeshNode* >::iterator u2n = u2Nodes.begin();
+ for ( ; u2n != u2Nodes.end(); ++u2n )
+ edgeNodes.push_back( u2n->second );
+ if ( edge->Orientation() == TopAbs_REVERSED )
+ edgeNodes.reverse();
+
+ if ( !nodes.empty() && nodes.back() == edgeNodes.front() )
+ edgeNodes.pop_front();
+ nodes.splice( nodes.end(), edgeNodes, edgeNodes.begin(), edgeNodes.end() );
+ }
+
+ // get length of structured sides
+ vector<int> nbEdgesInSide;
+ int nbEdges = 0;
+ list< const SMDS_MeshNode* >::iterator n = ++nodes.begin();
+ for ( ; n != nodes.end(); ++n )
+ {
+ ++nbEdges;
+ if ( isCornerOfStructure( *n, fSM, faceAnalyser )) {
+ nbEdgesInSide.push_back( nbEdges );
+ nbEdges = 0;
+ }
+ }
+
+ // checks
+ if ( nbEdgesInSide.size() != 4 )
+ return false;
+ if ( nbEdgesInSide[0] != nbEdgesInSide[2] )
+ return false;
+ if ( nbEdgesInSide[1] != nbEdgesInSide[3] )
+ return false;
+ if ( nbEdgesInSide[0] * nbEdgesInSide[1] != fSM->NbElements() )
+ return false;
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Find out elements orientation on a geometrical face
+ * \param theFace - The face correctly oriented in the shape being meshed
+ * \retval bool - true if the face normal and the normal of first element
+ * in the correspoding submesh point in different directions
+ */
+//================================================================================
+
+bool SMESH_MesherHelper::IsReversedSubMesh (const TopoDS_Face& theFace)
+{
+ if ( theFace.IsNull() )
+ return false;
+
+ // find out orientation of a meshed face
+ int faceID = GetMeshDS()->ShapeToIndex( theFace );
+ TopoDS_Shape aMeshedFace = GetMeshDS()->IndexToShape( faceID );
+ bool isReversed = ( theFace.Orientation() != aMeshedFace.Orientation() );
+
+ const SMESHDS_SubMesh * aSubMeshDSFace = GetMeshDS()->MeshElements( faceID );
+ if ( !aSubMeshDSFace )
+ return isReversed;
+
+ // find an element with a good normal
+ gp_Vec Ne;
+ bool normalOK = false;
+ gp_XY uv;
+ SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
+ while ( !normalOK && iteratorElem->more() ) // loop on elements on theFace
+ {
+ const SMDS_MeshElement* elem = iteratorElem->next();
+ if ( elem && elem->NbCornerNodes() > 2 )
+ {
+ SMESH_TNodeXYZ nPnt[3];
+ SMDS_ElemIteratorPtr nodesIt = elem->nodesIterator();
+ for ( int iN = 0; nodesIt->more() && iN < 3; ++iN) // loop on nodes
+ nPnt[ iN ] = nodesIt->next();
+
+ // compute normal
+ gp_Vec v01( nPnt[0], nPnt[1] ), v02( nPnt[0], nPnt[2] );
+ if ( v01.SquareMagnitude() > RealSmall() &&
+ v02.SquareMagnitude() > RealSmall() )
+ {
+ Ne = v01 ^ v02;
+ if (( normalOK = ( Ne.SquareMagnitude() > RealSmall() )))
+ uv = GetNodeUV( theFace, nPnt[0]._node, nPnt[2]._node, &normalOK );
+ }
+ }
+ }
+ if ( !normalOK )
+ return isReversed;
+
+ // face normal at node position
+ TopLoc_Location loc;
+ Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace, loc );
+ // if ( surf.IsNull() || surf->Continuity() < GeomAbs_C1 )
+ // some surfaces not detected as GeomAbs_C1 are nevertheless correct for meshing
+ if ( surf.IsNull() || surf->Continuity() < GeomAbs_C0 )
+ {
+ if (!surf.IsNull())
+ MESSAGE("surf->Continuity() < GeomAbs_C1 " << (surf->Continuity() < GeomAbs_C1));
+ return isReversed;
+ }
+ gp_Vec d1u, d1v; gp_Pnt p;
+ surf->D1( uv.X(), uv.Y(), p, d1u, d1v );
+ gp_Vec Nf = (d1u ^ d1v).Transformed( loc );
+
+ if ( theFace.Orientation() == TopAbs_REVERSED )
+ Nf.Reverse();
+
+ return Ne * Nf < 0.;
+}
+
+//=======================================================================
+//function : Count
+//purpose : Count nb of sub-shapes
+//=======================================================================
+
+int SMESH_MesherHelper::Count(const TopoDS_Shape& shape,
+ const TopAbs_ShapeEnum type,
+ const bool ignoreSame)
+{
+ if ( ignoreSame ) {
+ TopTools_IndexedMapOfShape map;
+ TopExp::MapShapes( shape, type, map );
+ return map.Extent();
+ }
+ else {
+ int nb = 0;
+ for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() )
+ ++nb;
+ return nb;