+ // TopoDS_Face FF1[2], FF2[2];
+ // PShapeIteratorPtr fIt = helper.GetAncestors(E1, *_mesh, TopAbs_FACE);
+ // while ( fIt->more() && FF1[1].IsNull() )
+ // {
+ // const TopoDS_Face *F = (const TopoDS_Face*) fIt->next();
+ // if ( helper.IsSubShape( *F, data._solid))
+ // FF1[ FF1[0].IsNull() ? 0 : 1 ] = *F;
+ // }
+ // fIt = helper.GetAncestors(E2, *_mesh, TopAbs_FACE);
+ // while ( fIt->more() && FF2[1].IsNull())
+ // {
+ // const TopoDS_Face *F = (const TopoDS_Face*) fIt->next();
+ // if ( helper.IsSubShape( *F, data._solid))
+ // FF2[ FF2[0].IsNull() ? 0 : 1 ] = *F;
+ // }
+ // // exclude a FACE common to E1 and E2 (put it to FFn[1] )
+ // if ( FF1[0].IsSame( FF2[0]) || FF1[0].IsSame( FF2[1]))
+ // std::swap( FF1[0], FF1[1] );
+ // if ( FF2[0].IsSame( FF1[0]) )
+ // std::swap( FF2[0], FF2[1] );
+ // if ( FF1[0].IsNull() || FF2[0].IsNull() )
+ // continue;
+
+ // get a new normal for edge1
+ //bool ok;
+ gp_Vec dir1 = edge1->_normal, dir2 = edge2->_normal;
+ // if ( edge1->_cosin < 0 )
+ // dir1 = getFaceDir( FF1[0], E1, edge1->_nodes[0], helper, ok ).Normalized();
+ // if ( edge2->_cosin < 0 )
+ // dir2 = getFaceDir( FF2[0], E2, edge2->_nodes[0], helper, ok ).Normalized();
+
+ 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 );
+ newEdge._normal = ( wgt1 * dir1 + wgt2 * dir2 ).XYZ();
+ newEdge._normal.Normalize();
+
+ // cout << edge1->_nodes[0]->GetID() << " "
+ // << edge2->_nodes[0]->GetID() << " NORM: "
+ // << newEdge._normal.X() << ", " << newEdge._normal.Y() << ", " << newEdge._normal.Z() << endl;
+
+ // get new cosin
+ if ( cos1 < theMinSmoothCosin )
+ {
+ newEdge._cosin = edge2->_cosin;
+ }
+ else if ( cos2 > theMinSmoothCosin ) // both cos1 and cos2 > theMinSmoothCosin
+ {
+ // gp_Vec dirInFace;
+ // if ( edge1->_cosin < 0 )
+ // dirInFace = dir1;
+ // else
+ // dirInFace = getFaceDir( FF1[0], E1, edge1->_nodes[0], helper, ok );
+ // double angle = dirInFace.Angle( edge1->_normal ); // [0,PI]
+ // edge1->SetCosin( Cos( angle ));
+ //newEdge._cosin = 0; // ???????????
+ newEdge._cosin = ( wgt1 * cos1 + wgt2 * cos2 ) * edge1->_cosin / cos1;
+ }
+ else
+ {
+ newEdge._cosin = edge1->_cosin;
+ }
+
+ // find shapes that need smoothing due to change of _normal
+ if ( edge1->_cosin < theMinSmoothCosin &&
+ newEdge._cosin > theMinSmoothCosin )
+ {
+ if ( eos1->_sWOL.IsNull() )
+ {
+ SMDS_ElemIteratorPtr fIt = edge1->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() )
+ shapesToSmooth.insert( data.GetShapeEdges( fIt->next()->getshapeId() ));
+ //limitStepSize( data, fIt->next(), edge1->_cosin ); // too late
+ }
+ else // edge1 inflates along a FACE
+ {
+ TopoDS_Shape V = helper.GetSubShapeByNode( edge1->_nodes[0], getMeshDS() );
+ PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE );
+ while ( const TopoDS_Shape* E = eIt->next() )
+ {
+ if ( !helper.IsSubShape( *E, /*FACE=*/eos1->_sWOL ))
+ continue;
+ 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 ));
+ }
+ }
+ }
+ }
+
+ data.AddShapesToSmooth( shapesToSmooth );
+
+ // Update data of edges depending on a new _normal
+
+ for ( size_t iE = 0; iE < edge2newEdge.size(); ++iE )
+ {
+ _LayerEdge* edge1 = edge2newEdge[ iE ].first;
+ _LayerEdge& newEdge = edge2newEdge[ iE ].second;
+ if ( !edge1 ) continue;
+ _EdgesOnShape* eos1 = data.GetShapeEdges( edge1 );
+ if ( !eos1 ) continue;
+
+ edge1->_normal = newEdge._normal;
+ edge1->SetCosin( newEdge._cosin );
+ edge1->InvalidateStep( 1, *eos1 );
+ edge1->_len = 0;
+ edge1->SetNewLength( data._stepSize, *eos1, helper );
+ 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 );
+ }
+
+ // Update normals and other dependent data of not intersecting _LayerEdge's
+ // neighboring the intersecting ones
+
+ if ( !edge1->_2neibors )
+ continue;
+ for ( int j = 0; j < 2; ++j ) // loop on 2 neighbors
+ {
+ _LayerEdge* neighbor = edge1->_2neibors->_edges[j];
+ if ( edge2CloseEdge.count ( neighbor ))
+ continue; // j-th neighbor is also intersected
+ _EdgesOnShape* eos = data.GetShapeEdges( neighbor );
+ if ( !eos ) continue;
+ _LayerEdge* prevEdge = edge1;
+ const int nbSteps = 10;
+ for ( int step = nbSteps; step; --step ) // step from edge1 in j-th direction
+ {
+ if ( !neighbor->_2neibors )
+ break; // neighbor is on VERTEX
+ int iNext = 0;
+ _LayerEdge* nextEdge = neighbor->_2neibors->_edges[iNext];
+ if ( nextEdge == prevEdge )
+ nextEdge = neighbor->_2neibors->_edges[ ++iNext ];
+ double r = double(step-1)/nbSteps;
+ if ( !nextEdge->_2neibors )
+ r = 0.5;
+
+ gp_XYZ newNorm = prevEdge->_normal * r + nextEdge->_normal * (1-r);
+ newNorm.Normalize();
+
+ neighbor->_normal = newNorm;
+ neighbor->SetCosin( prevEdge->_cosin * r + nextEdge->_cosin * (1-r) );
+ neighbor->SetDataByNeighbors( prevEdge->_nodes[0], nextEdge->_nodes[0], *eos, helper );
+
+ neighbor->InvalidateStep( 1, *eos );
+ neighbor->_len = 0;
+ neighbor->SetNewLength( data._stepSize, *eos, helper );
+
+ // goto the next neighbor
+ prevEdge = neighbor;
+ neighbor = nextEdge;
+ }
+ }
+ }
+ dumpFunctionEnd();
+ }
+ // 2) Check absence of intersections
+ // TODO?
+
+ for ( size_t i = 0 ; i < tmpFaces.size(); ++i )
+ delete tmpFaces[i];
+
+ return true;
+}
+
+//================================================================================
+/*!
+ * \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 ]->_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 );
+ _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, helper );
+ 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 ]->_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, _EdgesOnShape* >::iterator id2eos = convFace._subIdToEOS.find( faceID );
+ if ( id2eos != convFace._subIdToEOS.end() )