+ updateNormalsOfC1Vertices( data );
+
+ if ( stepNb > 0 && !updateNormalsOfConvexFaces( data, helper, stepNb ))
+ return false;
+
+ // map to store new _normal and _cosin for each intersected edge
+ map< _LayerEdge*, _LayerEdge, _LayerEdgeCmp > edge2newEdge;
+ map< _LayerEdge*, _LayerEdge, _LayerEdgeCmp >::iterator e2neIt;
+ _LayerEdge zeroEdge;
+ zeroEdge._normal.SetCoord( 0,0,0 );
+ zeroEdge._maxLen = Precision::Infinite();
+ zeroEdge._nodes.resize(1); // to init _TmpMeshFaceOnEdge
+
+ set< _EdgesOnShape* > shapesToSmooth, edgesNoAnaSmooth;
+
+ double segLen, dist1, dist2, dist;
+ vector< pair< _LayerEdge*, double > > intEdgesDist;
+ _TmpMeshFaceOnEdge quad( &zeroEdge, &zeroEdge, 0 );
+
+ for ( int iter = 0; iter < 5; ++iter )
+ {
+ edge2newEdge.clear();
+
+ for ( size_t iE = 0; iE < data._collisionEdges.size(); ++iE )
+ {
+ _CollisionEdges& ce = data._collisionEdges[iE];
+ _LayerEdge* edge1 = ce._edge;
+ if ( !edge1 /*|| edge1->Is( _LayerEdge::BLOCKED )*/) continue;
+ _EdgesOnShape* eos1 = data.GetShapeEdges( edge1 );
+ if ( !eos1 ) continue;
+
+ // detect intersections
+ gp_Ax1 lastSeg = edge1->LastSegment( segLen, *eos1 );
+ double testLen = 1.5 * edge1->_maxLen * edge1->_lenFactor;
+ double eps = 0.5;
+ intEdgesDist.clear();
+ double minIntDist = Precision::Infinite();
+ for ( size_t i = 0; i < ce._intEdges.size(); i += 2 )
+ {
+ if ( edge1->Is( _LayerEdge::BLOCKED ) &&
+ ce._intEdges[i ]->Is( _LayerEdge::BLOCKED ) &&
+ ce._intEdges[i+1]->Is( _LayerEdge::BLOCKED ))
+ continue;
+ double dot = edge1->_normal * quad.GetDir( ce._intEdges[i], ce._intEdges[i+1] );
+ double fact = ( 1.1 + dot * dot );
+ SMESH_TNodeXYZ pSrc0( ce.nSrc(i) ), pSrc1( ce.nSrc(i+1) );
+ SMESH_TNodeXYZ pTgt0( ce.nTgt(i) ), pTgt1( ce.nTgt(i+1) );
+ gp_XYZ pLast0 = pSrc0 + ( pTgt0 - pSrc0 ) * fact;
+ gp_XYZ pLast1 = pSrc1 + ( pTgt1 - pSrc1 ) * fact;
+ dist1 = dist2 = Precision::Infinite();
+ if ( !edge1->SegTriaInter( lastSeg, pSrc0, pLast0, pSrc1, dist1, eps ) &&
+ !edge1->SegTriaInter( lastSeg, pSrc1, pLast1, pLast0, dist2, eps ))
+ continue;
+ dist = dist1;
+ if ( dist > testLen || dist <= 0 )
+ {
+ dist = dist2;
+ if ( dist > testLen || dist <= 0 )
+ continue;
+ }
+ // choose a closest edge
+ gp_Pnt intP( lastSeg.Location().XYZ() + lastSeg.Direction().XYZ() * ( dist + segLen ));
+ double d1 = intP.SquareDistance( pSrc0 );
+ double d2 = intP.SquareDistance( pSrc1 );
+ int iClose = i + ( d2 < d1 );
+ _LayerEdge* edge2 = ce._intEdges[iClose];
+ edge2->Unset( _LayerEdge::MARKED );
+
+ // choose a closest edge among neighbors
+ gp_Pnt srcP( SMESH_TNodeXYZ( edge1->_nodes[0] ));
+ d1 = srcP.SquareDistance( SMESH_TNodeXYZ( edge2->_nodes[0] ));
+ for ( size_t j = 0; j < intEdgesDist.size(); ++j )
+ {
+ _LayerEdge * edgeJ = intEdgesDist[j].first;
+ if ( edge2->IsNeiborOnEdge( edgeJ ))
+ {
+ d2 = srcP.SquareDistance( SMESH_TNodeXYZ( edgeJ->_nodes[0] ));
+ ( d1 < d2 ? edgeJ : edge2 )->Set( _LayerEdge::MARKED );
+ }
+ }
+ intEdgesDist.push_back( make_pair( edge2, dist ));
+ // if ( Abs( d2 - d1 ) / Max( d2, d1 ) < 0.5 )
+ // {
+ // iClose = i + !( d2 < d1 );
+ // intEdges.push_back( ce._intEdges[iClose] );
+ // ce._intEdges[iClose]->Unset( _LayerEdge::MARKED );
+ // }
+ minIntDist = Min( edge1->_len * edge1->_lenFactor - segLen + dist, minIntDist );
+ }
+
+ //ce._edge = 0;
+
+ // compute new _normals
+ for ( size_t i = 0; i < intEdgesDist.size(); ++i )
+ {
+ _LayerEdge* edge2 = intEdgesDist[i].first;
+ double distWgt = edge1->_len / intEdgesDist[i].second;
+ // if ( edge1->Is( _LayerEdge::BLOCKED ) &&
+ // edge2->Is( _LayerEdge::BLOCKED )) continue;
+ if ( edge2->Is( _LayerEdge::MARKED )) continue;
+ edge2->Set( _LayerEdge::MARKED );
+
+ // get a new normal
+ gp_XYZ dir1 = edge1->_normal, dir2 = edge2->_normal;
+
+ double cos1 = Abs( edge1->_cosin ), cos2 = Abs( edge2->_cosin );
+ double wgt1 = ( cos1 + 0.001 ) / ( cos1 + cos2 + 0.002 );
+ double wgt2 = ( cos2 + 0.001 ) / ( cos1 + cos2 + 0.002 );
+ // double cos1 = Abs( edge1->_cosin ), cos2 = Abs( edge2->_cosin );
+ // double sgn1 = 0.1 * ( 1 + edge1->_cosin ), sgn2 = 0.1 * ( 1 + edge2->_cosin );
+ // double wgt1 = ( cos1 + sgn1 ) / ( cos1 + cos2 + sgn1 + sgn2 );
+ // double wgt2 = ( cos2 + sgn2 ) / ( cos1 + cos2 + sgn1 + sgn2 );
+ gp_XYZ newNormal = wgt1 * dir1 + wgt2 * dir2;
+ newNormal.Normalize();
+
+ // get new cosin
+ double newCos;
+ double sgn1 = edge1->_cosin / cos1, sgn2 = edge2->_cosin / cos2;
+ if ( cos1 < theMinSmoothCosin )
+ {
+ newCos = cos2 * sgn1;
+ }
+ else if ( cos2 > theMinSmoothCosin ) // both cos1 and cos2 > theMinSmoothCosin
+ {
+ newCos = ( wgt1 * cos1 + wgt2 * cos2 ) * edge1->_cosin / cos1;
+ }
+ else
+ {
+ newCos = edge1->_cosin;
+ }
+
+ e2neIt = edge2newEdge.insert( make_pair( edge1, zeroEdge )).first;
+ e2neIt->second._normal += distWgt * newNormal;
+ e2neIt->second._cosin = newCos;
+ e2neIt->second._maxLen = 0.7 * minIntDist / edge1->_lenFactor;
+ if ( iter > 0 && sgn1 * sgn2 < 0 && edge1->_cosin < 0 )
+ e2neIt->second._normal += dir2;
+ e2neIt = edge2newEdge.insert( make_pair( edge2, zeroEdge )).first;
+ e2neIt->second._normal += distWgt * newNormal;
+ e2neIt->second._cosin = edge2->_cosin;
+ if ( iter > 0 && sgn1 * sgn2 < 0 && edge2->_cosin < 0 )
+ e2neIt->second._normal += dir1;
+ }
+ }
+
+ if ( edge2newEdge.empty() )
+ break; //return true;
+
+ dumpFunction(SMESH_Comment("updateNormals")<< data._index << "_" << stepNb << "_it" << iter);
+
+ // Update data of edges depending on a new _normal
+
+ data.UnmarkEdges();
+ for ( e2neIt = edge2newEdge.begin(); e2neIt != edge2newEdge.end(); ++e2neIt )
+ {
+ _LayerEdge* edge = e2neIt->first;
+ if ( edge->Is( _LayerEdge::BLOCKED )) continue;
+ _LayerEdge& newEdge = e2neIt->second;
+ _EdgesOnShape* eos = data.GetShapeEdges( edge );
+
+ // Check if a new _normal is OK:
+ newEdge._normal.Normalize();
+ if ( !isNewNormalOk( data, *edge, newEdge._normal ))
+ {
+ if ( newEdge._maxLen < edge->_len && iter > 0 ) // limit _maxLen
+ {
+ edge->InvalidateStep( stepNb + 1, *eos, /*restoreLength=*/true );
+ edge->_maxLen = newEdge._maxLen;
+ edge->SetNewLength( newEdge._maxLen, *eos, helper );
+ }
+ continue; // the new _normal is bad
+ }
+ // the new _normal is OK
+
+ // find shapes that need smoothing due to change of _normal
+ if ( edge->_cosin < theMinSmoothCosin &&
+ newEdge._cosin > theMinSmoothCosin )
+ {
+ if ( eos->_sWOL.IsNull() )
+ {
+ SMDS_ElemIteratorPtr fIt = edge->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() )
+ shapesToSmooth.insert( data.GetShapeEdges( fIt->next()->getshapeId() ));
+ }
+ else // edge inflates along a FACE
+ {
+ TopoDS_Shape V = helper.GetSubShapeByNode( edge->_nodes[0], getMeshDS() );
+ PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE, &eos->_sWOL );
+ while ( const TopoDS_Shape* E = eIt->next() )
+ {
+ gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( *E ), TopoDS::Vertex( V ));
+ double angle = edgeDir.Angle( newEdge._normal ); // [0,PI]
+ if ( angle < M_PI / 2 )
+ shapesToSmooth.insert( data.GetShapeEdges( *E ));
+ }
+ }
+ }
+
+ double len = edge->_len;
+ edge->InvalidateStep( stepNb + 1, *eos, /*restoreLength=*/true );
+ edge->SetNormal( newEdge._normal );
+ edge->SetCosin( newEdge._cosin );
+ edge->SetNewLength( len, *eos, helper );
+ edge->Set( _LayerEdge::MARKED );
+ edge->Set( _LayerEdge::NORMAL_UPDATED );
+ edgesNoAnaSmooth.insert( eos );
+ }
+
+ // Update normals and other dependent data of not intersecting _LayerEdge's
+ // neighboring the intersecting ones
+
+ for ( e2neIt = edge2newEdge.begin(); e2neIt != edge2newEdge.end(); ++e2neIt )
+ {
+ _LayerEdge* edge1 = e2neIt->first;
+ _EdgesOnShape* eos1 = data.GetShapeEdges( edge1 );
+ if ( !edge1->Is( _LayerEdge::MARKED ))
+ continue;
+
+ if ( edge1->IsOnEdge() )
+ {
+ const SMDS_MeshNode * n1 = edge1->_2neibors->srcNode(0);
+ const SMDS_MeshNode * n2 = edge1->_2neibors->srcNode(1);
+ edge1->SetDataByNeighbors( n1, n2, *eos1, helper );
+ }
+
+ if ( !edge1->_2neibors || !eos1->_sWOL.IsNull() )
+ continue;
+ for ( int j = 0; j < 2; ++j ) // loop on 2 neighbors
+ {
+ _LayerEdge* neighbor = edge1->_2neibors->_edges[j];
+ if ( neighbor->Is( _LayerEdge::MARKED ) /*edge2newEdge.count ( neighbor )*/)
+ continue; // j-th neighbor is also intersected
+ _LayerEdge* prevEdge = edge1;
+ const int nbSteps = 10;
+ for ( int step = nbSteps; step; --step ) // step from edge1 in j-th direction
+ {
+ if ( neighbor->Is( _LayerEdge::BLOCKED ) ||
+ neighbor->Is( _LayerEdge::MARKED ))
+ break;
+ _EdgesOnShape* eos = data.GetShapeEdges( neighbor );
+ if ( !eos ) continue;
+ _LayerEdge* nextEdge = neighbor;
+ if ( neighbor->_2neibors )
+ {
+ int iNext = 0;
+ nextEdge = neighbor->_2neibors->_edges[iNext];
+ if ( nextEdge == prevEdge )
+ nextEdge = neighbor->_2neibors->_edges[ ++iNext ];
+ }
+ double r = double(step-1)/nbSteps/(iter+1);
+ if ( !nextEdge->_2neibors )
+ r = Min( r, 0.5 );
+
+ gp_XYZ newNorm = prevEdge->_normal * r + nextEdge->_normal * (1-r);
+ newNorm.Normalize();
+ if ( !isNewNormalOk( data, *neighbor, newNorm ))
+ break;
+
+ double len = neighbor->_len;
+ neighbor->InvalidateStep( stepNb + 1, *eos, /*restoreLength=*/true );
+ neighbor->SetNormal( newNorm );
+ neighbor->SetCosin( prevEdge->_cosin * r + nextEdge->_cosin * (1-r) );
+ if ( neighbor->_2neibors )
+ neighbor->SetDataByNeighbors( prevEdge->_nodes[0], nextEdge->_nodes[0], *eos, helper );
+ neighbor->SetNewLength( len, *eos, helper );
+ neighbor->Set( _LayerEdge::MARKED );
+ neighbor->Set( _LayerEdge::NORMAL_UPDATED );
+ edgesNoAnaSmooth.insert( eos );
+
+ if ( !neighbor->_2neibors )
+ break; // neighbor is on VERTEX
+
+ // goto the next neighbor
+ prevEdge = neighbor;
+ neighbor = nextEdge;
+ }
+ }
+ }
+ dumpFunctionEnd();
+ } // iterations
+
+ data.AddShapesToSmooth( shapesToSmooth, &edgesNoAnaSmooth );
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Check if a new normal is OK
+ */
+//================================================================================
+
+bool _ViscousBuilder::isNewNormalOk( _SolidData& data,
+ _LayerEdge& edge,
+ const gp_XYZ& newNormal)
+{
+ // check a min angle between the newNormal and surrounding faces
+ vector<_Simplex> simplices;
+ SMESH_TNodeXYZ n0( edge._nodes[0] ), n1, n2;
+ _Simplex::GetSimplices( n0._node, simplices, data._ignoreFaceIds, &data );
+ double newMinDot = 1, curMinDot = 1;
+ for ( size_t i = 0; i < simplices.size(); ++i )
+ {
+ n1.Set( simplices[i]._nPrev );
+ n2.Set( simplices[i]._nNext );
+ gp_XYZ normFace = ( n1 - n0 ) ^ ( n2 - n0 );
+ double normLen2 = normFace.SquareModulus();
+ if ( normLen2 < std::numeric_limits<double>::min() )
+ continue;
+ normFace /= Sqrt( normLen2 );
+ newMinDot = Min( newNormal * normFace, newMinDot );
+ curMinDot = Min( edge._normal * normFace, curMinDot );
+ }
+ bool ok = true;
+ if ( newMinDot < 0.5 )
+ {
+ ok = ( newMinDot >= curMinDot * 0.9 );
+ //return ( newMinDot >= ( curMinDot * ( 0.8 + 0.1 * edge.NbSteps() )));
+ // double initMinDot2 = 1. - edge._cosin * edge._cosin;
+ // return ( newMinDot * newMinDot ) >= ( 0.8 * initMinDot2 );
+ }
+
+ return ok;
+}
+
+//================================================================================
+/*!
+ * \brief Modify normals of _LayerEdge's on FACE to reflex smoothing
+ */
+//================================================================================
+
+bool _ViscousBuilder::updateNormalsOfSmoothed( _SolidData& data,
+ SMESH_MesherHelper& helper,
+ const int nbSteps,
+ const double stepSize )
+{
+ if ( data._nbShapesToSmooth == 0 || nbSteps == 0 )
+ return true; // no shapes needing smoothing
+
+ for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS )
+ {
+ _EdgesOnShape& eos = data._edgesOnShape[ iS ];
+ if ( //!eos._toSmooth || _eosC1 have _toSmooth == false
+ !eos._hyp.ToSmooth() ||
+ eos.ShapeType() != TopAbs_FACE ||
+ eos._edges.empty() )
+ continue;
+
+ bool toSmooth = ( eos._edges[ 0 ]->NbSteps() >= nbSteps+1 );
+ if ( !toSmooth ) continue;
+
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* edge = eos._edges[i];
+ if ( !edge->Is( _LayerEdge::SMOOTHED ))
+ continue;
+ if ( edge->Is( _LayerEdge::DIFFICULT ) && nbSteps != 1 )
+ continue;
+
+ const gp_XYZ& pPrev = edge->PrevPos();
+ const gp_XYZ& pLast = edge->_pos.back();
+ gp_XYZ stepVec = pLast - pPrev;
+ double realStepSize = stepVec.Modulus();
+ if ( realStepSize < numeric_limits<double>::min() )
+ continue;
+
+ edge->_lenFactor = realStepSize / stepSize;
+ edge->_normal = stepVec / realStepSize;
+ edge->Set( _LayerEdge::NORMAL_UPDATED );
+ }
+ }
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Modify normals of _LayerEdge's on C1 VERTEXes
+ */
+//================================================================================
+
+void _ViscousBuilder::updateNormalsOfC1Vertices( _SolidData& data )
+{
+ for ( size_t iS = 0; iS < data._edgesOnShape.size(); ++iS )
+ {
+ _EdgesOnShape& eov = data._edgesOnShape[ iS ];
+ if ( eov._eosC1.empty() ||
+ eov.ShapeType() != TopAbs_VERTEX ||
+ eov._edges.empty() )
+ continue;
+
+ gp_XYZ newNorm = eov._edges[0]->_normal;
+ double curThick = eov._edges[0]->_len * eov._edges[0]->_lenFactor;
+ bool normChanged = false;
+
+ for ( size_t i = 0; i < eov._eosC1.size(); ++i )
+ {
+ _EdgesOnShape* eoe = eov._eosC1[i];
+ const TopoDS_Edge& e = TopoDS::Edge( eoe->_shape );
+ const double eLen = SMESH_Algo::EdgeLength( e );
+ TopoDS_Shape oppV = SMESH_MesherHelper::IthVertex( 0, e );
+ if ( oppV.IsSame( eov._shape ))
+ oppV = SMESH_MesherHelper::IthVertex( 1, e );
+ _EdgesOnShape* eovOpp = data.GetShapeEdges( oppV );
+ if ( !eovOpp || eovOpp->_edges.empty() ) continue;
+ if ( eov._edges[0]->Is( _LayerEdge::BLOCKED )) continue;
+
+ double curThickOpp = eovOpp->_edges[0]->_len * eovOpp->_edges[0]->_lenFactor;
+ if ( curThickOpp + curThick < eLen )
+ continue;
+
+ double wgt = 2. * curThick / eLen;
+ newNorm += wgt * eovOpp->_edges[0]->_normal;
+ normChanged = true;
+ }
+ if ( normChanged )
+ {
+ eov._edges[0]->SetNormal( newNorm.Normalized() );
+ eov._edges[0]->Set( _LayerEdge::NORMAL_UPDATED );
+ }
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Modify normals of _LayerEdge's on _ConvexFace's
+ */
+//================================================================================
+
+bool _ViscousBuilder::updateNormalsOfConvexFaces( _SolidData& data,
+ SMESH_MesherHelper& helper,
+ int stepNb )
+{
+ SMESHDS_Mesh* meshDS = helper.GetMeshDS();
+ bool isOK;
+
+ map< TGeomID, _ConvexFace >::iterator id2face = data._convexFaces.begin();
+ for ( ; id2face != data._convexFaces.end(); ++id2face )
+ {
+ _ConvexFace & convFace = (*id2face).second;
+ if ( convFace._normalsFixed )
+ continue; // already fixed
+ if ( convFace.CheckPrisms() )
+ continue; // nothing to fix
+
+ convFace._normalsFixed = true;
+
+ BRepAdaptor_Surface surface ( convFace._face, false );
+ BRepLProp_SLProps surfProp( surface, 2, 1e-6 );
+
+ // check if the convex FACE is of spherical shape
+
+ Bnd_B3d centersBox; // bbox of centers of curvature of _LayerEdge's on VERTEXes
+ Bnd_B3d nodesBox;
+ gp_Pnt center;
+
+ map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.begin();
+ for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos )
+ {
+ _EdgesOnShape& eos = *(id2eos->second);
+ if ( eos.ShapeType() == TopAbs_VERTEX )
+ {
+ _LayerEdge* ledge = eos._edges[ 0 ];
+ if ( convFace.GetCenterOfCurvature( ledge, surfProp, helper, center ))
+ centersBox.Add( center );
+ }
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ nodesBox.Add( SMESH_TNodeXYZ( eos._edges[ i ]->_nodes[0] ));
+ }
+ if ( centersBox.IsVoid() )
+ {
+ 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;
+ id2eos = convFace._subIdToEOS.begin();
+ for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos )
+ {
+ _EdgesOnShape& eos = *(id2eos->second);
+ // set data of _CentralCurveOnEdge
+ if ( eos.ShapeType() == TopAbs_EDGE )
+ {
+ _CentralCurveOnEdge& ceCurve = centerCurves[ nbEdges++ ];
+ ceCurve.SetShapes( TopoDS::Edge( eos._shape ), convFace, data, helper );
+ if ( !eos._sWOL.IsNull() )
+ ceCurve._adjFace.Nullify();
+ else
+ ceCurve._ledges.insert( ceCurve._ledges.end(),
+ eos._edges.begin(), eos._edges.end());
+ }
+ // summarize normals
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ avgNormal += eos._edges[ i ]->_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
+ id2eos = convFace._subIdToEOS.begin();
+ for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos )
+ {
+ _EdgesOnShape& eos = *(id2eos->second);
+ if ( eos.ShapeType() != TopAbs_EDGE )
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ eos._edges[ i ]->_cosin = avgCosin;
+
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ eos._edges[ i ]->SetNormal( avgNormal );
+ eos._edges[ i ]->Set( _LayerEdge::NORMAL_UPDATED );
+ }
+ }
+ }
+ 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 );
+ _EdgesOnShape* eos = data.GetShapeEdges( edgeID );
+ if ( !eos || eos->_edges.empty() )
+ {
+ // 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 );
+ eos = data.GetShapeEdges( vID );
+ vertexLEdges[ iV ] = eos->_edges[ 0 ];
+ }
+ edgeLEdge = &vertexLEdges[0];
+ edgeLEdgeEnd = edgeLEdge + 2;
+
+ centerCurves[ iE ]._adjFace.Nullify();
+ }
+ else
+ {
+ if ( ! eos->_toSmooth )
+ data.SortOnEdge( edge, eos->_edges );
+ edgeLEdge = &eos->_edges[ 0 ];
+ edgeLEdgeEnd = edgeLEdge + eos->_edges.size();
+ vertexLEdges[0] = eos->_edges.front()->_2neibors->_edges[0];
+ vertexLEdges[1] = eos->_edges.back() ->_2neibors->_edges[1];
+
+ if ( ! eos->_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 ]->SetNormal( centerCurves[ iE ]._normals[ iLE ]);
+ centerCurves[ iE ]._ledges[ iLE ]->Set( _LayerEdge::NORMAL_UPDATED );
+ }
+ }
+ // 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 ]->SetNormal( newNorm );
+ centerCurves[ iE ]._ledges[ iLE ]->_cosin = newCosin;
+ centerCurves[ iE ]._ledges[ iLE ]->Set( _LayerEdge::NORMAL_UPDATED );
+ }
+ }
+
+ // Find new normals for _LayerEdge's based on FACE
+
+ if ( nbCosin > 0 )
+ avgCosin /= nbCosin;
+ const TGeomID faceID = meshDS->ShapeToIndex( convFace._face );
+ map< TGeomID, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.find( faceID );
+ if ( id2eos != convFace._subIdToEOS.end() )
+ {
+ int iE = 0;
+ gp_XYZ newNorm;
+ _EdgesOnShape& eos = * ( id2eos->second );
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* ledge = eos._edges[ i ];
+ 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->SetNormal( newNorm );
+ ledge->_cosin = avgCosin;
+ ledge->Set( _LayerEdge::NORMAL_UPDATED );
+ 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 ));
+
+ id2eos = convFace._subIdToEOS.begin();
+ for ( ; id2eos != convFace._subIdToEOS.end(); ++id2eos )
+ {
+ _EdgesOnShape& eos = * ( id2eos->second );
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* & ledge = eos._edges[ i ];
+ double len = ledge->_len;
+ ledge->InvalidateStep( stepNb + 1, eos, /*restoreLength=*/true );
+ ledge->SetCosin( ledge->_cosin );
+ ledge->SetNewLength( len, eos, helper );
+ }
+ if ( eos.ShapeType() != TopAbs_FACE )
+ for ( size_t i = 0; i < eos._edges.size(); ++i )
+ {
+ _LayerEdge* ledge = eos._edges[ i ];
+ for ( size_t iN = 0; iN < ledge->_neibors.size(); ++iN )
+ {
+ _LayerEdge* neibor = ledge->_neibors[iN];
+ if ( neibor->_nodes[0]->GetPosition()->GetDim() == 2 )
+ {
+ neibor->Set( _LayerEdge::NEAR_BOUNDARY );
+ neibor->Set( _LayerEdge::MOVED );
+ neibor->SetSmooLen( neibor->_len );
+ }
+ }
+ }
+ } // 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< _EdgesOnShape* > 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( data.GetShapeEdges( 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
+ */
+//================================================================================
+
+bool _ConvexFace::GetCenterOfCurvature( _LayerEdge* ledge,
+ BRepLProp_SLProps& surfProp,
+ SMESH_MesherHelper& helper,
+ gp_Pnt & center ) const
+{
+ gp_XY uv = helper.GetNodeUV( _face, ledge->_nodes[0] );