+
+//================================================================================
+namespace // data for smoothing
+{
+ struct TSmoothNode;
+ // --------------------------------------------------------------------------------
+ /*!
+ * \brief Structure used to check validity of node position after smoothing.
+ * It holds two nodes connected to a smoothed node and belonging to
+ * one mesh face
+ */
+ struct TTriangle
+ {
+ TSmoothNode* _n1;
+ TSmoothNode* _n2;
+ TTriangle( TSmoothNode* n1=0, TSmoothNode* n2=0 ): _n1(n1), _n2(n2) {}
+
+ inline bool IsForward( gp_UV uv ) const;
+ };
+ // --------------------------------------------------------------------------------
+ /*!
+ * \brief Data of a smoothed node
+ */
+ struct TSmoothNode
+ {
+ gp_XY _uv;
+ vector< TTriangle > _triangles; // if empty, then node is not movable
+ };
+ // --------------------------------------------------------------------------------
+ inline bool TTriangle::IsForward( gp_UV uv ) const
+ {
+ gp_Vec2d v1( uv, _n1->_uv ), v2( uv, _n2->_uv );
+ double d = v1 ^ v2;
+ return d > 1e-100;
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Set UV of nodes on degenerated VERTEXes in the middle of degenerated EDGE
+ *
+ * WARNING: this method must be called AFTER retrieving UVPtStruct's from quad
+ */
+//================================================================================
+
+void StdMeshers_Quadrangle_2D::UpdateDegenUV(FaceQuadStruct* quad)
+{
+ for ( unsigned i = 0; i < quad->side.size(); ++i )
+ {
+ StdMeshers_FaceSide* side = quad->side[i];
+ const vector<UVPtStruct>& uvVec = side->GetUVPtStruct();
+
+ // find which end of the side is on degenerated shape
+ int degenInd = -1;
+ if ( myHelper->IsDegenShape( uvVec[0].node->getshapeId() ))
+ degenInd = 0;
+ else if ( myHelper->IsDegenShape( uvVec.back().node->getshapeId() ))
+ degenInd = uvVec.size() - 1;
+ else
+ continue;
+
+ // find another side sharing the degenerated shape
+ bool isPrev = ( degenInd == 0 );
+ if ( i >= TOP_SIDE )
+ isPrev = !isPrev;
+ int i2 = ( isPrev ? ( i + 3 ) : ( i + 1 )) % 4;
+ StdMeshers_FaceSide* side2 = quad->side[ i2 ];
+ const vector<UVPtStruct>& uvVec2 = side2->GetUVPtStruct();
+ int degenInd2 = -1;
+ if ( uvVec[ degenInd ].node == uvVec2[0].node )
+ degenInd2 = 0;
+ else if ( uvVec[ degenInd ].node == uvVec2.back().node )
+ degenInd2 = uvVec2.size() - 1;
+ else
+ throw SALOME_Exception( LOCALIZED( "Logical error" ));
+
+ // move UV in the middle
+ uvPtStruct& uv1 = const_cast<uvPtStruct&>( uvVec [ degenInd ]);
+ uvPtStruct& uv2 = const_cast<uvPtStruct&>( uvVec2[ degenInd2 ]);
+ uv1.u = uv2.u = 0.5 * ( uv1.u + uv2.u );
+ uv1.v = uv2.v = 0.5 * ( uv1.v + uv2.v );
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Perform smoothing of 2D elements on a FACE with ignored degenerated EDGE
+ */
+//================================================================================
+
+void StdMeshers_Quadrangle_2D::Smooth (FaceQuadStruct* quad)
+{
+ if ( !myNeedSmooth ) return;
+
+ // Get nodes to smooth
+
+ typedef map< const SMDS_MeshNode*, TSmoothNode, TIDCompare > TNo2SmooNoMap;
+ TNo2SmooNoMap smooNoMap;
+
+ const TopoDS_Face& geomFace = TopoDS::Face( myHelper->GetSubShape() );
+ SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
+ SMESHDS_SubMesh* fSubMesh = meshDS->MeshElements( geomFace );
+ SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
+ while ( nIt->more() ) // loop on nodes bound to a FACE
+ {
+ const SMDS_MeshNode* node = nIt->next();
+ TSmoothNode & sNode = smooNoMap[ node ];
+ sNode._uv = myHelper->GetNodeUV( geomFace, node );
+
+ // set sNode._triangles
+ SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ {
+ const SMDS_MeshElement* face = fIt->next();
+ const int nbN = face->NbCornerNodes();
+ const int nInd = face->GetNodeIndex( node );
+ const int prevInd = myHelper->WrapIndex( nInd - 1, nbN );
+ const int nextInd = myHelper->WrapIndex( nInd + 1, nbN );
+ const SMDS_MeshNode* prevNode = face->GetNode( prevInd );
+ const SMDS_MeshNode* nextNode = face->GetNode( nextInd );
+ sNode._triangles.push_back( TTriangle( & smooNoMap[ prevNode ],
+ & smooNoMap[ nextNode ]));
+ }
+ }
+ // set _uv of smooth nodes on FACE boundary
+ for ( unsigned i = 0; i < quad->side.size(); ++i )
+ {
+ const vector<UVPtStruct>& uvVec = quad->side[i]->GetUVPtStruct();
+ for ( unsigned j = 0; j < uvVec.size(); ++j )
+ {
+ TSmoothNode & sNode = smooNoMap[ uvVec[j].node ];
+ sNode._uv.SetCoord( uvVec[j].u, uvVec[j].v );
+ }
+ }
+
+ // define refernce orientation in 2D
+ TNo2SmooNoMap::iterator n2sn = smooNoMap.begin();
+ for ( ; n2sn != smooNoMap.end(); ++n2sn )
+ if ( !n2sn->second._triangles.empty() )
+ break;
+ if ( n2sn == smooNoMap.end() ) return;
+ const TSmoothNode & sampleNode = n2sn->second;
+ const bool refForward = ( sampleNode._triangles[0].IsForward( sampleNode._uv ));
+
+ // Smoothing
+
+ for ( int iLoop = 0; iLoop < 5; ++iLoop )
+ {
+ for ( n2sn = smooNoMap.begin(); n2sn != smooNoMap.end(); ++n2sn )
+ {
+ TSmoothNode& sNode = n2sn->second;
+ if ( sNode._triangles.empty() )
+ continue; // not movable node
+
+ // compute a new UV
+ gp_XY newUV (0,0);
+ for ( unsigned i = 0; i < sNode._triangles.size(); ++i )
+ newUV += sNode._triangles[i]._n1->_uv;
+ newUV /= sNode._triangles.size();
+
+ // check validity of the newUV
+ bool isValid = true;
+ for ( unsigned i = 0; i < sNode._triangles.size() && isValid; ++i )
+ isValid = ( sNode._triangles[i].IsForward( newUV ) == refForward );
+
+ if ( isValid )
+ sNode._uv = newUV;
+ }
+ }
+
+ // Set new XYZ to the smoothed nodes
+
+ Handle(Geom_Surface) surface = BRep_Tool::Surface( geomFace );
+
+ for ( n2sn = smooNoMap.begin(); n2sn != smooNoMap.end(); ++n2sn )
+ {
+ TSmoothNode& sNode = n2sn->second;
+ if ( sNode._triangles.empty() )
+ continue; // not movable node
+
+ SMDS_MeshNode* node = const_cast< SMDS_MeshNode*>( n2sn->first );
+ gp_Pnt xyz = surface->Value( sNode._uv.X(), sNode._uv.Y() );
+ meshDS->MoveNode( node, xyz.X(), xyz.Y(), xyz.Z() );
+
+ // store the new UV
+ node->SetPosition( SMDS_PositionPtr( new SMDS_FacePosition( sNode._uv.X(), sNode._uv.Y() )));
+ }
+
+ // Move medium nodes in quadratic mesh
+ if ( _quadraticMesh )
+ {
+ const TLinkNodeMap& links = myHelper->GetTLinkNodeMap();
+ TLinkNodeMap::const_iterator linkIt = links.begin();
+ for ( ; linkIt != links.end(); ++linkIt )
+ {
+ const SMESH_TLink& link = linkIt->first;
+ SMDS_MeshNode* node = const_cast< SMDS_MeshNode*>( linkIt->second );
+
+ if ( node->getshapeId() != myHelper->GetSubShapeID() )
+ continue; // medium node is on EDGE or VERTEX
+
+ gp_XY uv1 = myHelper->GetNodeUV( geomFace, link.node1(), node );
+ gp_XY uv2 = myHelper->GetNodeUV( geomFace, link.node2(), node );
+
+ gp_XY uv = myHelper->GetMiddleUV( surface, uv1, uv2 );
+ node->SetPosition( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
+
+ gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
+ meshDS->MoveNode( node, xyz.X(), xyz.Y(), xyz.Z() );
+ }
+ }
+}