+ debugMsg( "Error: centersBox.IsVoid()" );
+ return false;
+ }
+ const bool isSpherical =
+ ( centersBox.SquareExtent() < 1e-6 * nodesBox.SquareExtent() );
+
+ int nbEdges = helper.Count( convFace._face, TopAbs_EDGE, /*ignoreSame=*/false );
+ vector < _CentralCurveOnEdge > centerCurves( nbEdges );
+
+ if ( isSpherical )
+ {
+ // set _LayerEdge::_normal as average of all normals
+
+ // WARNING: different density of nodes on EDGEs is not taken into account that
+ // can lead to an improper new normal
+
+ gp_XYZ avgNormal( 0,0,0 );
+ nbEdges = 0;
+ id2end = convFace._subIdToEdgeEnd.begin();
+ for ( ; id2end != convFace._subIdToEdgeEnd.end(); ++id2end )
+ {
+ data.GetEdgesOnShape( id2end->second, iBeg, iEnd );
+ // set data of _CentralCurveOnEdge
+ const TopoDS_Shape& S = meshDS->IndexToShape( id2end->first );
+ if ( S.ShapeType() == TopAbs_EDGE )
+ {
+ _CentralCurveOnEdge& ceCurve = centerCurves[ nbEdges++ ];
+ ceCurve.SetShapes( TopoDS::Edge(S), convFace, data, helper );
+ if ( !data._edges[ iBeg ]->_sWOL.IsNull() )
+ ceCurve._adjFace.Nullify();
+ else
+ ceCurve._ledges.insert( ceCurve._ledges.end(),
+ &data._edges[ iBeg ], &data._edges[ iEnd ]);
+ }
+ // summarize normals
+ for ( ; iBeg < iEnd; ++iBeg )
+ avgNormal += data._edges[ iBeg ]->_normal;
+ }
+ double normSize = avgNormal.SquareModulus();
+ if ( normSize < 1e-200 )
+ {
+ debugMsg( "updateNormalsOfConvexFaces(): zero avgNormal" );
+ return false;
+ }
+ avgNormal /= Sqrt( normSize );
+
+ // compute new _LayerEdge::_cosin on EDGEs
+ double avgCosin = 0;
+ int nbCosin = 0;
+ gp_Vec inFaceDir;
+ for ( size_t iE = 0; iE < centerCurves.size(); ++iE )
+ {
+ _CentralCurveOnEdge& ceCurve = centerCurves[ iE ];
+ if ( ceCurve._adjFace.IsNull() )
+ continue;
+ for ( size_t iLE = 0; iLE < ceCurve._ledges.size(); ++iLE )
+ {
+ const SMDS_MeshNode* node = ceCurve._ledges[ iLE ]->_nodes[0];
+ inFaceDir = getFaceDir( ceCurve._adjFace, ceCurve._edge, node, helper, isOK );
+ if ( isOK )
+ {
+ double angle = inFaceDir.Angle( avgNormal ); // [0,PI]
+ ceCurve._ledges[ iLE ]->_cosin = Cos( angle );
+ avgCosin += ceCurve._ledges[ iLE ]->_cosin;
+ nbCosin++;
+ }
+ }
+ }
+ if ( nbCosin > 0 )
+ avgCosin /= nbCosin;
+
+ // set _LayerEdge::_normal = avgNormal
+ id2end = convFace._subIdToEdgeEnd.begin();
+ for ( ; id2end != convFace._subIdToEdgeEnd.end(); ++id2end )
+ {
+ data.GetEdgesOnShape( id2end->second, iBeg, iEnd );
+ const TopoDS_Shape& S = meshDS->IndexToShape( id2end->first );
+ if ( S.ShapeType() != TopAbs_EDGE )
+ for ( int i = iBeg; i < iEnd; ++i )
+ data._edges[ i ]->_cosin = avgCosin;
+
+ for ( ; iBeg < iEnd; ++iBeg )
+ data._edges[ iBeg ]->_normal = avgNormal;
+ }
+ }
+ else // if ( isSpherical )
+ {
+ // We suppose that centers of curvature at all points of the FACE
+ // lie on some curve, let's call it "central curve". For all _LayerEdge's
+ // having a common center of curvature we define the same new normal
+ // as a sum of normals of _LayerEdge's on EDGEs among them.
+
+ // get all centers of curvature for each EDGE
+
+ helper.SetSubShape( convFace._face );
+ _LayerEdge* vertexLEdges[2], **edgeLEdge, **edgeLEdgeEnd;
+
+ TopExp_Explorer edgeExp( convFace._face, TopAbs_EDGE );
+ for ( int iE = 0; edgeExp.More(); edgeExp.Next(), ++iE )
+ {
+ const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() );
+
+ // set adjacent FACE
+ centerCurves[ iE ].SetShapes( edge, convFace, data, helper );
+
+ // get _LayerEdge's of the EDGE
+ TGeomID edgeID = meshDS->ShapeToIndex( edge );
+ id2end = convFace._subIdToEdgeEnd.find( edgeID );
+ if ( id2end == convFace._subIdToEdgeEnd.end() )
+ {
+ // no _LayerEdge's on EDGE, use _LayerEdge's on VERTEXes
+ for ( int iV = 0; iV < 2; ++iV )
+ {
+ TopoDS_Vertex v = helper.IthVertex( iV, edge );
+ TGeomID vID = meshDS->ShapeToIndex( v );
+ int end = convFace._subIdToEdgeEnd[ vID ];
+ int iBeg = end > 0 ? data._endEdgeOnShape[ end-1 ] : 0;
+ vertexLEdges[ iV ] = data._edges[ iBeg ];
+ }
+ edgeLEdge = &vertexLEdges[0];
+ edgeLEdgeEnd = edgeLEdge + 2;
+
+ centerCurves[ iE ]._adjFace.Nullify();
+ }
+ else
+ {
+ data.GetEdgesOnShape( id2end->second, iBeg, iEnd );
+ if ( id2end->second >= data._nbShapesToSmooth )
+ data.SortOnEdge( edge, iBeg, iEnd, helper );
+ edgeLEdge = &data._edges[ iBeg ];
+ edgeLEdgeEnd = edgeLEdge + iEnd - iBeg;
+ vertexLEdges[0] = data._edges[ iBeg ]->_2neibors->_edges[0];
+ vertexLEdges[1] = data._edges[ iEnd-1 ]->_2neibors->_edges[1];
+
+ if ( ! data._edges[ iBeg ]->_sWOL.IsNull() )
+ centerCurves[ iE ]._adjFace.Nullify();
+ }
+
+ // Get curvature centers
+
+ centersBox.Clear();
+
+ if ( edgeLEdge[0]->IsOnEdge() &&
+ convFace.GetCenterOfCurvature( vertexLEdges[0], surfProp, helper, center ))
+ { // 1st VERTEX
+ centerCurves[ iE ].Append( center, vertexLEdges[0] );
+ centersBox.Add( center );
+ }
+ for ( ; edgeLEdge < edgeLEdgeEnd; ++edgeLEdge )
+ if ( convFace.GetCenterOfCurvature( *edgeLEdge, surfProp, helper, center ))
+ { // EDGE or VERTEXes
+ centerCurves[ iE ].Append( center, *edgeLEdge );
+ centersBox.Add( center );
+ }
+ if ( edgeLEdge[-1]->IsOnEdge() &&
+ convFace.GetCenterOfCurvature( vertexLEdges[1], surfProp, helper, center ))
+ { // 2nd VERTEX
+ centerCurves[ iE ].Append( center, vertexLEdges[1] );
+ centersBox.Add( center );
+ }
+ centerCurves[ iE ]._isDegenerated =
+ ( centersBox.IsVoid() || centersBox.SquareExtent() < 1e-6 * nodesBox.SquareExtent() );
+
+ } // loop on EDGES of convFace._face to set up data of centerCurves
+
+ // Compute new normals for _LayerEdge's on EDGEs
+
+ double avgCosin = 0;
+ int nbCosin = 0;
+ gp_Vec inFaceDir;
+ for ( size_t iE1 = 0; iE1 < centerCurves.size(); ++iE1 )
+ {
+ _CentralCurveOnEdge& ceCurve = centerCurves[ iE1 ];
+ if ( ceCurve._isDegenerated )
+ continue;
+ const vector< gp_Pnt >& centers = ceCurve._curvaCenters;
+ vector< gp_XYZ > & newNormals = ceCurve._normals;
+ for ( size_t iC1 = 0; iC1 < centers.size(); ++iC1 )
+ {
+ isOK = false;
+ for ( size_t iE2 = 0; iE2 < centerCurves.size() && !isOK; ++iE2 )
+ {
+ if ( iE1 != iE2 )
+ isOK = centerCurves[ iE2 ].FindNewNormal( centers[ iC1 ], newNormals[ iC1 ]);
+ }
+ if ( isOK && !ceCurve._adjFace.IsNull() )
+ {
+ // compute new _LayerEdge::_cosin
+ const SMDS_MeshNode* node = ceCurve._ledges[ iC1 ]->_nodes[0];
+ inFaceDir = getFaceDir( ceCurve._adjFace, ceCurve._edge, node, helper, isOK );
+ if ( isOK )
+ {
+ double angle = inFaceDir.Angle( newNormals[ iC1 ] ); // [0,PI]
+ ceCurve._ledges[ iC1 ]->_cosin = Cos( angle );
+ avgCosin += ceCurve._ledges[ iC1 ]->_cosin;
+ nbCosin++;
+ }
+ }
+ }
+ }
+ // set new normals to _LayerEdge's of NOT degenerated central curves
+ for ( size_t iE = 0; iE < centerCurves.size(); ++iE )
+ {
+ if ( centerCurves[ iE ]._isDegenerated )
+ continue;
+ for ( size_t iLE = 0; iLE < centerCurves[ iE ]._ledges.size(); ++iLE )
+ centerCurves[ iE ]._ledges[ iLE ]->_normal = centerCurves[ iE ]._normals[ iLE ];
+ }
+ // set new normals to _LayerEdge's of degenerated central curves
+ for ( size_t iE = 0; iE < centerCurves.size(); ++iE )
+ {
+ if ( !centerCurves[ iE ]._isDegenerated ||
+ centerCurves[ iE ]._ledges.size() < 3 )
+ continue;
+ // new normal is an average of new normals at VERTEXes that
+ // was computed on non-degenerated _CentralCurveOnEdge's
+ gp_XYZ newNorm = ( centerCurves[ iE ]._ledges.front()->_normal +
+ centerCurves[ iE ]._ledges.back ()->_normal );
+ double sz = newNorm.Modulus();
+ if ( sz < 1e-200 )
+ continue;
+ newNorm /= sz;
+ double newCosin = ( 0.5 * centerCurves[ iE ]._ledges.front()->_cosin +
+ 0.5 * centerCurves[ iE ]._ledges.back ()->_cosin );
+ for ( size_t iLE = 1, nb = centerCurves[ iE ]._ledges.size() - 1; iLE < nb; ++iLE )
+ {
+ centerCurves[ iE ]._ledges[ iLE ]->_normal = newNorm;
+ centerCurves[ iE ]._ledges[ iLE ]->_cosin = newCosin;
+ }
+ }
+
+ // Find new normals for _LayerEdge's based on FACE
+
+ if ( nbCosin > 0 )
+ avgCosin /= nbCosin;
+ const TGeomID faceID = meshDS->ShapeToIndex( convFace._face );
+ map< TGeomID, int >::iterator id2end = convFace._subIdToEdgeEnd.find( faceID );
+ if ( id2end != convFace._subIdToEdgeEnd.end() )
+ {
+ int iE = 0;
+ gp_XYZ newNorm;
+ data.GetEdgesOnShape( id2end->second, iBeg, iEnd );
+ for ( ; iBeg < iEnd; ++iBeg )
+ {
+ _LayerEdge* ledge = data._edges[ iBeg ];
+ if ( !convFace.GetCenterOfCurvature( ledge, surfProp, helper, center ))
+ continue;
+ for ( size_t i = 0; i < centerCurves.size(); ++i, ++iE )
+ {
+ iE = iE % centerCurves.size();
+ if ( centerCurves[ iE ]._isDegenerated )
+ continue;
+ newNorm.SetCoord( 0,0,0 );
+ if ( centerCurves[ iE ].FindNewNormal( center, newNorm ))
+ {
+ ledge->_normal = newNorm;
+ ledge->_cosin = avgCosin;
+ break;
+ }
+ }
+ }
+ }
+
+ } // not a quasi-spherical FACE
+
+ // Update _LayerEdge's data according to a new normal
+
+ dumpFunction(SMESH_Comment("updateNormalsOfConvexFaces")<<data._index
+ <<"_F"<<meshDS->ShapeToIndex( convFace._face ));
+
+ id2end = convFace._subIdToEdgeEnd.begin();
+ for ( ; id2end != convFace._subIdToEdgeEnd.end(); ++id2end )
+ {
+ data.GetEdgesOnShape( id2end->second, iBeg, iEnd );
+ for ( ; iBeg < iEnd; ++iBeg )
+ {
+ _LayerEdge* & ledge = data._edges[ iBeg ];
+ double len = ledge->_len;
+ ledge->InvalidateStep( stepNb + 1, /*restoreLength=*/true );
+ ledge->SetCosin( ledge->_cosin );
+ ledge->SetNewLength( len, helper );
+ }
+
+ } // loop on sub-shapes of convFace._face
+
+ // Find FACEs adjacent to convFace._face that got necessity to smooth
+ // as a result of normals modification
+
+ set< TGeomID > adjFacesToSmooth;
+ for ( size_t iE = 0; iE < centerCurves.size(); ++iE )
+ {
+ if ( centerCurves[ iE ]._adjFace.IsNull() ||
+ centerCurves[ iE ]._adjFaceToSmooth )
+ continue;
+ for ( size_t iLE = 0; iLE < centerCurves[ iE ]._ledges.size(); ++iLE )
+ {
+ if ( centerCurves[ iE ]._ledges[ iLE ]->_cosin > theMinSmoothCosin )
+ {
+ adjFacesToSmooth.insert( meshDS->ShapeToIndex( centerCurves[ iE ]._adjFace ));
+ break;
+ }
+ }
+ }
+ data.AddShapesToSmooth( adjFacesToSmooth );
+
+ dumpFunctionEnd();
+
+
+ } // loop on data._convexFaces
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds a center of curvature of a surface at a _LayerEdge
+ */
+//================================================================================