+ /* calculate V parameter and test bounds */
+ double v = (dir.XYZ() * qvec) / det;
+ //if ( v < 0.0 || u + v > 1.0 )
+ if ( v < -EPSILON || u + v > 1.0 + EPSILON)
+ return false;
+
+ /* calculate t, ray intersects triangle */
+ t = (edge2 * qvec) / det;
+
+ //return true;
+ return t > 0.;
+}
+
+//================================================================================
+/*!
+ * \brief Perform smooth of _LayerEdge's based on EDGE's
+ * \retval bool - true if node has been moved
+ */
+//================================================================================
+
+bool _LayerEdge::SmoothOnEdge(Handle(Geom_Surface)& surface,
+ const TopoDS_Face& F,
+ SMESH_MesherHelper& helper)
+{
+ ASSERT( IsOnEdge() );
+
+ SMDS_MeshNode* tgtNode = const_cast<SMDS_MeshNode*>( _nodes.back() );
+ SMESH_TNodeXYZ oldPos( tgtNode );
+ double dist01, distNewOld;
+
+ SMESH_TNodeXYZ p0( _2neibors->tgtNode(0));
+ SMESH_TNodeXYZ p1( _2neibors->tgtNode(1));
+ dist01 = p0.Distance( _2neibors->tgtNode(1) );
+
+ gp_Pnt newPos = p0 * _2neibors->_wgt[0] + p1 * _2neibors->_wgt[1];
+ double lenDelta = 0;
+ if ( _curvature )
+ {
+ //lenDelta = _curvature->lenDelta( _len );
+ lenDelta = _curvature->lenDeltaByDist( dist01 );
+ newPos.ChangeCoord() += _normal * lenDelta;
+ }
+
+ distNewOld = newPos.Distance( oldPos );
+
+ if ( F.IsNull() )
+ {
+ if ( _2neibors->_plnNorm )
+ {
+ // put newPos on the plane defined by source node and _plnNorm
+ gp_XYZ new2src = SMESH_TNodeXYZ( _nodes[0] ) - newPos.XYZ();
+ double new2srcProj = (*_2neibors->_plnNorm) * new2src;
+ newPos.ChangeCoord() += (*_2neibors->_plnNorm) * new2srcProj;
+ }
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ _pos.back() = newPos.XYZ();
+ }
+ else
+ {
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ gp_XY uv( Precision::Infinite(), 0 );
+ helper.CheckNodeUV( F, tgtNode, uv, 1e-10, /*force=*/true );
+ _pos.back().SetCoord( uv.X(), uv.Y(), 0 );
+
+ newPos = surface->Value( uv.X(), uv.Y() );
+ tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
+ }
+
+ // commented for IPAL0052478
+ // if ( _curvature && lenDelta < 0 )
+ // {
+ // gp_Pnt prevPos( _pos[ _pos.size()-2 ]);
+ // _len -= prevPos.Distance( oldPos );
+ // _len += prevPos.Distance( newPos );
+ // }
+ bool moved = distNewOld > dist01/50;
+ //if ( moved )
+ dumpMove( tgtNode ); // debug
+
+ return moved;
+}
+
+//================================================================================
+/*!
+ * \brief Perform laplacian smooth in 3D of nodes inflated from FACE
+ * \retval bool - true if _tgtNode has been moved
+ */
+//================================================================================
+
+bool _LayerEdge::Smooth(int& badNb, const int step, const bool isConcaveFace )
+{
+ bool moved = false;
+ if ( _simplices.size() < 2 )
+ return moved; // _LayerEdge inflated along EDGE or FACE
+
+ const gp_XYZ& curPos ( _pos.back() );
+ const gp_XYZ& prevPos( _pos[ _pos.size()-2 ]);
+
+ // quality metrics (orientation) of tetras around _tgtNode
+ int nbOkBefore = 0;
+ double vol, minVolBefore = 1e100;
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ nbOkBefore += _simplices[i].IsForward( _nodes[0], &curPos, vol );
+ minVolBefore = Min( minVolBefore, vol );
+ }
+ int nbBad = _simplices.size() - nbOkBefore;
+
+ // compute new position for the last _pos using different _funs
+ gp_XYZ newPos, bestNewPos;
+ for ( int iFun = -1; iFun < theNbSmooFuns; ++iFun )
+ {
+ if ( iFun < 0 )
+ newPos = (this->*_smooFunction)(); // fun chosen by ChooseSmooFunction()
+ else if ( _funs[ iFun ] == _smooFunction )
+ continue; // _smooFunction again
+ else if ( step > 0 )
+ newPos = (this->*_funs[ iFun ])(); // try other smoothing fun
+ else
+ break; // let "easy" functions improve elements around distorted ones
+
+ if ( _curvature )
+ {
+ double delta = _curvature->lenDelta( _len );
+ if ( delta > 0 )
+ newPos += _normal * delta;
+ else
+ {
+ double segLen = _normal * ( newPos - prevPos );
+ if ( segLen + delta > 0 )
+ newPos += _normal * delta;
+ }
+ // double segLenChange = _normal * ( curPos - newPos );
+ // newPos += 0.5 * _normal * segLenChange;
+ }
+
+ int nbOkAfter = 0;
+ double minVolAfter = 1e100;
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos, vol );
+ minVolAfter = Min( minVolAfter, vol );
+ }
+ // get worse?
+ if ( nbOkAfter < nbOkBefore )
+ continue;
+ if (( isConcaveFace ) &&
+ ( nbOkAfter == nbOkBefore ) &&
+ //( iFun > -1 || nbOkAfter < _simplices.size() ) &&
+ ( minVolAfter <= minVolBefore ))
+ continue;
+
+ SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() );
+
+ // commented for IPAL0052478
+ // _len -= prevPos.Distance(SMESH_TNodeXYZ( n ));
+ // _len += prevPos.Distance(newPos);
+
+ n->setXYZ( newPos.X(), newPos.Y(), newPos.Z());
+ _pos.back() = newPos;
+ moved = true;
+ dumpMoveComm( n, _funNames[ iFun < 0 ? smooFunID() : iFun ]);
+
+ nbBad = _simplices.size() - nbOkAfter;
+
+ if ( iFun > -1 )
+ {
+ //_smooFunction = _funs[ iFun ];
+ // cout << "# " << _funNames[ iFun ] << "\t N:" << _nodes.back()->GetID()
+ // << "\t nbBad: " << _simplices.size() - nbOkAfter
+ // << " minVol: " << minVolAfter
+ // << " " << newPos.X() << " " << newPos.Y() << " " << newPos.Z()
+ // << endl;
+ minVolBefore = minVolAfter;
+ nbOkBefore = nbOkAfter;
+ continue; // look for a better function
+ }
+
+ break;
+
+ } // loop on smoothing functions
+
+ badNb += nbBad;
+ return moved;
+}
+
+//================================================================================
+/*!
+ * \brief Chooses a smoothing technic giving a position most close to an initial one.
+ * For a correct result, _simplices must contain nodes lying on geometry.
+ */
+//================================================================================
+
+void _LayerEdge::ChooseSmooFunction( const set< TGeomID >& concaveVertices,
+ const TNode2Edge& n2eMap)
+{
+ if ( _smooFunction ) return;
+
+ // use smoothNefPolygon() near concaveVertices
+ if ( !concaveVertices.empty() )
+ {
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ if ( concaveVertices.count( _simplices[i]._nPrev->getshapeId() ))
+ {
+ _smooFunction = _funs[ FUN_NEFPOLY ];
+
+ // set FUN_CENTROIDAL to neighbor edges
+ TNode2Edge::const_iterator n2e;
+ for ( i = 0; i < _simplices.size(); ++i )
+ {
+ if (( _simplices[i]._nPrev->GetPosition()->GetDim() == 2 ) &&
+ (( n2e = n2eMap.find( _simplices[i]._nPrev )) != n2eMap.end() ))
+ {
+ n2e->second->_smooFunction = _funs[ FUN_CENTROIDAL ];
+ }
+ }
+ return;
+ }
+ }
+ //}
+
+ // this coice is done only if ( !concaveVertices.empty() ) for Grids/smesh/bugs_19/X1
+ // where the nodes are smoothed too far along a sphere thus creating
+ // inverted _simplices
+ double dist[theNbSmooFuns];
+ //double coef[theNbSmooFuns] = { 1., 1.2, 1.4, 1.4 };
+ double coef[theNbSmooFuns] = { 1., 1., 1., 1. };
+
+ double minDist = Precision::Infinite();
+ gp_Pnt p = SMESH_TNodeXYZ( _nodes[0] );
+ for ( int i = 0; i < FUN_NEFPOLY; ++i )
+ {
+ gp_Pnt newP = (this->*_funs[i])();
+ dist[i] = p.SquareDistance( newP );
+ if ( dist[i]*coef[i] < minDist )
+ {
+ _smooFunction = _funs[i];
+ minDist = dist[i]*coef[i];
+ }
+ }
+ }
+ else
+ {
+ _smooFunction = _funs[ FUN_LAPLACIAN ];
+ }
+ // int minDim = 3;
+ // for ( size_t i = 0; i < _simplices.size(); ++i )
+ // minDim = Min( minDim, _simplices[i]._nPrev->GetPosition()->GetDim() );
+ // if ( minDim == 0 )
+ // _smooFunction = _funs[ FUN_CENTROIDAL ];
+ // else if ( minDim == 1 )
+ // _smooFunction = _funs[ FUN_CENTROIDAL ];
+
+
+ // int iMin;
+ // for ( int i = 0; i < FUN_NB; ++i )
+ // {
+ // //cout << dist[i] << " ";
+ // if ( _smooFunction == _funs[i] ) {
+ // iMin = i;
+ // //debugMsg( fNames[i] );
+ // break;
+ // }
+ // }
+ // cout << _funNames[ iMin ] << "\t N:" << _nodes.back()->GetID() << endl;
+}
+
+//================================================================================
+/*!
+ * \brief Returns a name of _SmooFunction
+ */
+//================================================================================
+
+int _LayerEdge::smooFunID( _LayerEdge::PSmooFun fun) const
+{
+ if ( !fun )
+ fun = _smooFunction;
+ for ( int i = 0; i < theNbSmooFuns; ++i )
+ if ( fun == _funs[i] )
+ return i;
+
+ return theNbSmooFuns;
+}
+
+//================================================================================
+/*!
+ * \brief Computes a new node position using Laplacian smoothing
+ */
+//================================================================================
+
+gp_XYZ _LayerEdge::smoothLaplacian()
+{
+ gp_XYZ newPos (0,0,0);
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ newPos += SMESH_TNodeXYZ( _simplices[i]._nPrev );
+ newPos /= _simplices.size();
+
+ return newPos;
+}
+
+//================================================================================
+/*!
+ * \brief Computes a new node position using angular-based smoothing
+ */
+//================================================================================
+
+gp_XYZ _LayerEdge::smoothAngular()
+{
+ vector< gp_Vec > edgeDir; edgeDir. reserve( _simplices.size() + 1);
+ vector< double > edgeSize; edgeSize.reserve( _simplices.size() );
+ vector< gp_XYZ > points; points. reserve( _simplices.size() );
+
+ gp_XYZ pPrev = SMESH_TNodeXYZ( _simplices.back()._nPrev );
+ gp_XYZ pN( 0,0,0 );
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ {
+ gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev );
+ edgeDir.push_back( p - pPrev );
+ edgeSize.push_back( edgeDir.back().Magnitude() );
+ //double edgeSize = edgeDir.back().Magnitude();
+ if ( edgeSize.back() < numeric_limits<double>::min() )
+ {
+ edgeDir.pop_back();
+ edgeSize.pop_back();
+ }
+ else
+ {
+ edgeDir.back() /= edgeSize.back();
+ points.push_back( p );
+ pN += p;
+ }
+ pPrev = p;
+ }
+ edgeDir.push_back ( edgeDir[0] );
+ edgeSize.push_back( edgeSize[0] );
+ pN /= points.size();
+
+ gp_XYZ newPos(0,0,0);
+ //gp_XYZ pN = SMESH_TNodeXYZ( _nodes.back() );
+ double sumSize = 0;
+ for ( size_t i = 0; i < points.size(); ++i )
+ {
+ gp_Vec toN( pN - points[i]);
+ double toNLen = toN.Magnitude();
+ if ( toNLen < numeric_limits<double>::min() )
+ {
+ newPos += pN;
+ continue;
+ }
+ gp_Vec bisec = edgeDir[i] + edgeDir[i+1];
+ double bisecLen = bisec.SquareMagnitude();
+ if ( bisecLen < numeric_limits<double>::min() )
+ {
+ gp_Vec norm = edgeDir[i] ^ toN;
+ bisec = norm ^ edgeDir[i];
+ bisecLen = bisec.SquareMagnitude();
+ }
+ bisecLen = Sqrt( bisecLen );
+ bisec /= bisecLen;