+//=======================================================================
+//function : IsDistorted2D
+//purpose : Return true if 2D mesh on FACE is ditorted
+//=======================================================================
+
+bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM,
+ bool checkUV,
+ SMESH_MesherHelper* faceHelper)
+{
+ if ( !faceSM || faceSM->GetSubShape().ShapeType() != TopAbs_FACE )
+ return false;
+
+ bool haveBadFaces = false;
+
+ SMESH_MesherHelper helper( *faceSM->GetFather() );
+ if ( faceHelper )
+ helper.CopySubShapeInfo( *faceHelper );
+ helper.SetSubShape( faceSM->GetSubShape() );
+
+ const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() );
+ SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F );
+ if ( !smDS || smDS->NbElements() == 0 ) return false;
+
+ bool subIdsValid = true; // shape ID of nodes is OK
+ if ( helper.HasSeam() )
+ {
+ // check if nodes are bound to seam edges
+ SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(/*includeSelf=*/false);
+ while ( smIt->more() && subIdsValid )
+ {
+ SMESH_subMesh* sm = smIt->next();
+ if ( helper.IsSeamShape( sm->GetId() ) && sm->IsEmpty() )
+ subIdsValid = false;
+ }
+ }
+ SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
+ double prevArea = 0;
+ vector< const SMDS_MeshNode* > nodes;
+ vector< gp_XY > uv;
+ bool* toCheckUV = checkUV ? & checkUV : 0;
+ while ( faceIt->more() && !haveBadFaces )
+ {
+ const SMDS_MeshElement* face = faceIt->next();
+
+ // get nodes
+ nodes.resize( face->NbCornerNodes() );
+ SMDS_MeshElement::iterator n = face->begin_nodes();
+ for ( size_t i = 0; i < nodes.size(); ++n, ++i )
+ nodes[ i ] = *n;
+
+ // avoid elems on degenerate shapes as UV on them can be wrong
+ if ( helper.HasDegeneratedEdges() )
+ {
+ bool isOnDegen = false;
+ for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i )
+ isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() );
+ if ( isOnDegen )
+ continue;
+ }
+ // prepare for getting UVs
+ const SMDS_MeshNode* inFaceNode = 0;
+ if ( helper.HasSeam() ) {
+ for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i )
+ if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() ))
+ {
+ inFaceNode = nodes[ i ];
+ if ( !subIdsValid )
+ {
+ gp_XY uv = helper.GetNodeUV( F, inFaceNode );
+ if ( helper.IsOnSeam( uv ))
+ inFaceNode = NULL;
+ }
+ }
+ if ( !inFaceNode )
+ continue;
+ }
+ // get UVs
+ uv.resize( nodes.size() );
+ for ( size_t i = 0; i < nodes.size(); ++i )
+ uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode, toCheckUV );
+
+ if ( !subIdsValid ) // fix uv on seam
+ {
+ gp_XY uvInFace = helper.GetNodeUV( F, inFaceNode );
+ for ( size_t i = 0; i < uv.size(); ++i )
+ if ( helper.IsOnSeam( uv[i] ))
+ uv[i] = helper.getUVOnSeam( uv[i], uvInFace ).XY();
+ }
+
+ // compare orientation of triangles
+ double faceArea = 0;
+ for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT )
+ {
+ gp_XY v1 = uv[ iT+1 ] - uv[ 0 ];
+ gp_XY v2 = uv[ iT+2 ] - uv[ 0 ];
+ faceArea += v2 ^ v1;
+ }
+ haveBadFaces = ( faceArea * prevArea < 0 );
+ prevArea = faceArea;
+ }
+
+ return haveBadFaces;
+}
+