+ theParams.clear();
+
+ double f = theFirstU, l = theLastU;
+
+ // Propagation Of Distribution
+ //
+ if ( !_mainEdge.IsNull() && _hypType == DISTRIB_PROPAGATION )
+ {
+ TopoDS_Edge mainEdge = TopoDS::Edge( _mainEdge ); // should not be a reference!
+ _gen->Compute( theMesh, mainEdge, SMESH_Gen::SHAPE_ONLY_UPWARD );
+
+ SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( mainEdge );
+ if ( !smDS )
+ return error("No mesh on the source edge of Propagation Of Distribution");
+ if ( smDS->NbNodes() < 1 )
+ return true; // 1 segment
+
+ map< double, const SMDS_MeshNode* > mainEdgeParamsOfNodes;
+ if ( ! SMESH_Algo::GetSortedNodesOnEdge( theMesh.GetMeshDS(), mainEdge, _quadraticMesh,
+ mainEdgeParamsOfNodes, SMDSAbs_Edge ))
+ return error("Bad node parameters on the source edge of Propagation Of Distribution");
+ vector< double > segLen( mainEdgeParamsOfNodes.size() - 1 );
+ double totalLen = 0;
+ BRepAdaptor_Curve mainEdgeCurve( mainEdge );
+ map< double, const SMDS_MeshNode* >::iterator
+ u_n2 = mainEdgeParamsOfNodes.begin(), u_n1 = u_n2++;
+ for ( size_t i = 1; i < mainEdgeParamsOfNodes.size(); ++i, ++u_n1, ++u_n2 )
+ {
+ segLen[ i-1 ] = GCPnts_AbscissaPoint::Length( mainEdgeCurve,
+ u_n1->first,
+ u_n2->first);
+ totalLen += segLen[ i-1 ];
+ }
+ for ( size_t i = 0; i < segLen.size(); ++i )
+ segLen[ i ] *= theLength / totalLen;
+
+ size_t iSeg = theReverse ? segLen.size()-1 : 0;
+ size_t dSeg = theReverse ? -1 : +1;
+ double param = theFirstU;
+ size_t nbParams = 0;
+ for ( size_t i = 1; i < segLen.size(); ++i, iSeg += dSeg )
+ {
+ double tol = Min( Precision::Confusion(), 0.01 * segLen[ iSeg ]);
+ GCPnts_AbscissaPoint Discret( tol, theC3d, segLen[ iSeg ], param );
+ if ( !Discret.IsDone() ) break;
+ param = Discret.Parameter();
+ theParams.push_back( param );
+ ++nbParams;
+ }
+ if ( nbParams != segLen.size()-1 )
+ return error( SMESH_Comment("Can't divide into ") << segLen.size() << " segments");
+
+ compensateError( segLen[ theReverse ? segLen.size()-1 : 0 ],
+ segLen[ theReverse ? 0 : segLen.size()-1 ],
+ f, l, theLength, theC3d, theParams, true );
+ return true;
+ }
+
+
+ switch( _hypType )
+ {
+ case LOCAL_LENGTH:
+ case MAX_LENGTH:
+ case NB_SEGMENTS:
+ {
+ double eltSize = 1;
+ smIdType nbSegments;
+ if ( _hypType == MAX_LENGTH )
+ {
+ double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
+ if (nbseg <= 0)
+ nbseg = 1; // degenerated edge
+ eltSize = theLength / nbseg * ( 1. - 1e-9 );
+ nbSegments = ToSmIdType( nbseg );
+ }
+ else if ( _hypType == LOCAL_LENGTH )
+ {
+ // Local Length hypothesis
+ double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
+
+ // NPAL17873:
+ bool isFound = false;
+ if (theConsiderPropagation && !_mainEdge.IsNull()) // propagated from some other edge
+ {
+ // Advanced processing to assure equal number of segments in case of Propagation
+ SMESH_subMesh* sm = theMesh.GetSubMeshContaining(_mainEdge);
+ if (sm) {
+ bool computed = sm->IsMeshComputed();
+ if (!computed) {
+ if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) {
+ _gen->Compute( theMesh, _mainEdge, /*anUpward=*/true);
+ computed = sm->IsMeshComputed();
+ }
+ }
+ if (computed) {
+ SMESHDS_SubMesh* smds = sm->GetSubMeshDS();
+ smIdType nb_segments = smds->NbElements();
+ if (nbseg - 1 <= nb_segments && nb_segments <= nbseg + 1) {
+ isFound = true;
+ nbseg = FromSmIdType<double>( nb_segments );
+ }
+ }
+ }
+ }
+ if (!isFound) // not found by meshed edge in the propagation chain, use precision
+ {
+ double aPrecision = _value[ PRECISION_IND ];
+ double nbseg_prec = ceil((theLength / _value[ BEG_LENGTH_IND ]) - aPrecision);
+ if (nbseg_prec == (nbseg - 1)) nbseg--;
+ }
+
+ if (nbseg <= 0)
+ nbseg = 1; // degenerated edge
+ eltSize = theLength / nbseg;
+ nbSegments = ToSmIdType( nbseg );
+ }
+ else
+ {
+ // Number Of Segments hypothesis
+ nbSegments = _ivalue[ NB_SEGMENTS_IND ];
+ if ( nbSegments < 1 ) return false;
+ if ( nbSegments == 1 ) return true;
+
+ switch (_ivalue[ DISTR_TYPE_IND ])
+ {
+ case StdMeshers_NumberOfSegments::DT_Scale:
+ {
+ double scale = _value[ SCALE_FACTOR_IND ];
+
+ if (fabs(scale - 1.0) < Precision::Confusion()) {
+ // special case to avoid division by zero
+ for ( smIdType i = 1; i < nbSegments; i++) {
+ double param = f + (l - f) * double( i ) / double( nbSegments );
+ theParams.push_back( param );
+ }
+ }
+ else { // general case of scale distribution
+ if ( theReverse )
+ scale = 1.0 / scale;
+
+ double alpha = pow(scale, 1.0 / double( nbSegments - 1 ));
+ double factor = (l - f) / (1.0 - pow(alpha, nbSegments));
+
+ for ( smIdType i = 1; i < nbSegments; i++) {
+ double param = f + factor * (1.0 - pow(alpha, i));
+ theParams.push_back( param );
+ }
+ }
+ const double lenFactor = theLength/(l-f);
+ const double minSegLen = Min( theParams.front() - f, l - theParams.back() );
+ const double tol = Min( Precision::Confusion(), 0.01 * minSegLen );
+ list<double>::iterator u = theParams.begin(), uEnd = theParams.end();
+ for ( ; u != uEnd; ++u )
+ {
+ GCPnts_AbscissaPoint Discret( tol, theC3d, ((*u)-f) * lenFactor, f );
+ if ( Discret.IsDone() )
+ *u = Discret.Parameter();
+ }
+ return true;
+ }
+ break;
+ case StdMeshers_NumberOfSegments::DT_TabFunc:
+ {
+ FunctionTable func(_vvalue[ TAB_FUNC_IND ], FromSmIdType<int>( _ivalue[ CONV_MODE_IND ]));
+ return computeParamByFunc(theC3d, f, l, theLength, theReverse,
+ _ivalue[ NB_SEGMENTS_IND ], func,
+ theParams);
+ }
+ break;
+ case StdMeshers_NumberOfSegments::DT_ExprFunc:
+ {
+ FunctionExpr func(_svalue[ EXPR_FUNC_IND ].c_str(),
+ FromSmIdType<int>( _ivalue[ CONV_MODE_IND ]));
+ return computeParamByFunc(theC3d, f, l, theLength, theReverse,
+ _ivalue[ NB_SEGMENTS_IND ], func,
+ theParams);
+ }
+ break;
+ case StdMeshers_NumberOfSegments::DT_Regular:
+ eltSize = theLength / double( nbSegments );
+ break;
+ default:
+ return false;
+ }
+ }
+
+ double tol = Min( Precision::Confusion(), 0.01 * eltSize );
+ divideIntoEqualSegments( theMesh, theC3d, nbSegments + 1, tol,
+ theLength, theFirstU, theLastU, theParams );
+
+ compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams, true ); // for PAL9899
+ return true;
+ }
+
+
+ case BEG_END_LENGTH: {
+
+ // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = theLength
+
+ double a1 = _value[ BEG_LENGTH_IND ];
+ double an = _value[ END_LENGTH_IND ];
+ double q = ( theLength - a1 ) / ( theLength - an );
+ if ( q < theLength/1e6 || 1.01*theLength < a1 + an)
+ return error ( SMESH_Comment("Invalid segment lengths (")<<a1<<" and "<<an<<") "<<
+ "for an edge of length "<<theLength);
+
+ double U1 = theReverse ? l : f;
+ double Un = theReverse ? f : l;
+ double param = U1;
+ double eltSize = theReverse ? -a1 : a1;
+ double tol = Min( Precision::Confusion(), 0.01 * Min( a1, an ));
+ while ( 1 ) {
+ // computes a point on a curve <theC3d> at the distance <eltSize>
+ // from the point of parameter <param>.
+ GCPnts_AbscissaPoint Discret( tol, theC3d, eltSize, param );
+ if ( !Discret.IsDone() ) break;
+ param = Discret.Parameter();
+ if ( f < param && param < l )
+ theParams.push_back( param );
+ else
+ break;
+ eltSize *= q;
+ }
+ compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
+ if (theReverse) theParams.reverse(); // NPAL18025
+ return true;
+ }
+
+ case ARITHMETIC_1D:
+ {
+ // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = theLength
+
+ double a1 = _value[ BEG_LENGTH_IND ];
+ double an = _value[ END_LENGTH_IND ];
+ if ( 1.01*theLength < a1 + an )
+ return error ( SMESH_Comment("Invalid segment lengths (")<<a1<<" and "<<an<<") "<<
+ "for an edge of length "<<theLength);
+
+ double q = ( an - a1 ) / ( 2 *theLength/( a1 + an ) - 1 );
+ int n = int(fabs(q) > numeric_limits<double>::min() ? ( 1+( an-a1 )/q ) : ( 1+theLength/a1 ));
+
+ double U1 = theReverse ? l : f;
+ double Un = theReverse ? f : l;
+ double param = U1;
+ double eltSize = a1;
+ double tol = Min( Precision::Confusion(), 0.01 * Min( a1, an ));
+ if ( theReverse ) {
+ eltSize = -eltSize;
+ q = -q;
+ }
+ while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
+ // computes a point on a curve <theC3d> at the distance <eltSize>
+ // from the point of parameter <param>.
+ GCPnts_AbscissaPoint Discret( tol, theC3d, eltSize, param );
+ if ( !Discret.IsDone() ) break;
+ param = Discret.Parameter();
+ if ( param > f && param < l )
+ theParams.push_back( param );
+ else
+ break;
+ eltSize += q;
+ }
+ compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
+ if ( theReverse ) theParams.reverse(); // NPAL18025
+
+ return true;
+ }
+
+ case GEOMETRIC_1D:
+ {
+ double a1 = _value[ BEG_LENGTH_IND ], an = 0;
+ double q = _value[ END_LENGTH_IND ];
+
+ double U1 = theReverse ? l : f;
+ double Un = theReverse ? f : l;
+ double param = U1;
+ double eltSize = a1;
+ if ( theReverse )
+ eltSize = -eltSize;
+
+ int nbParams = 0;
+ while ( true ) {
+ // computes a point on a curve <theC3d> at the distance <eltSize>
+ // from the point of parameter <param>.
+ double tol = Min( Precision::Confusion(), 0.01 * eltSize );
+ GCPnts_AbscissaPoint Discret( tol, theC3d, eltSize, param );
+ if ( !Discret.IsDone() ) break;
+ param = Discret.Parameter();
+ if ( f < param && param < l )
+ theParams.push_back( param );
+ else
+ break;
+ an = eltSize;
+ eltSize *= q;
+ ++nbParams;
+ if ( q < 1. && eltSize < 1e-100 )
+ return error("Too small common ratio causes too many segments");
+ }
+ if ( nbParams > 1 )
+ {
+ if ( Abs( param - Un ) < 0.2 * Abs( param - theParams.back() ))
+ {
+ compensateError( a1, Abs(eltSize), U1, Un, theLength, theC3d, theParams );
+ }
+ else if ( Abs( Un - theParams.back() ) <
+ 0.2 * Abs( theParams.back() - *(++theParams.rbegin())))
+ {
+ theParams.pop_back();
+ compensateError( a1, Abs(an), U1, Un, theLength, theC3d, theParams );
+ }
+ }
+ if (theReverse) theParams.reverse(); // NPAL18025
+
+ return true;
+ }
+
+ case FIXED_POINTS_1D:
+ {
+ const std::vector<double>& aPnts = _fpHyp->GetPoints();
+ std::vector<smIdType> nbsegs = _fpHyp->GetNbSegments();
+
+ // sort normalized params, taking into account theReverse
+ TColStd_SequenceOfReal Params;
+ double tol = 1e-7;
+ for ( size_t i = 0; i < aPnts.size(); i++ )
+ {
+ if( aPnts[i] < tol || aPnts[i] > 1 - tol )
+ continue;
+ double u = theReverse ? ( 1 - aPnts[i] ) : aPnts[i];
+ int j = 1;
+ bool IsExist = false;
+ for ( ; j <= Params.Length() && !IsExist; j++ )
+ {
+ IsExist = ( Abs( u - Params.Value(j) ) < tol );
+ if ( u < Params.Value(j) ) break;
+ }
+ if ( !IsExist ) Params.InsertBefore( j, u );
+ }
+ Params.InsertBefore( 1, 0.0 );
+ Params.Append( 1.0 );
+
+ if ( theReverse )
+ {
+ if ((int) nbsegs.size() > Params.Length() - 1 )
+ nbsegs.resize( Params.Length() - 1 );
+ std::reverse( nbsegs.begin(), nbsegs.end() );
+ }
+ if ( nbsegs.empty() )
+ {
+ nbsegs.push_back( 1 );
+ }
+ if ((int) nbsegs.size() < Params.Length() - 1 )
+ nbsegs.resize( Params.Length() - 1, nbsegs[0] );
+
+ // care of huge nbsegs - additionally divide diapasons
+ for ( int i = 2; i <= Params.Length(); i++ )
+ {
+ smIdType nbTot = nbsegs[ i-2 ];
+ if ( nbTot <= IntegerLast() )
+ continue;
+ smIdType nbDiapason = nbTot / IntegerLast() + 1;
+ smIdType nbSegPerDiap = nbTot / nbDiapason;
+ double par0 = Params( i - 1 ), par1 = Params( i );
+ for ( smIdType iDiap = 0; iDiap < nbDiapason - 1; ++iDiap )
+ {
+ double r = double( nbSegPerDiap * ( iDiap + 1 )) / double( nbTot );
+ double parI = par0 + ( par1 - par0 ) * r;
+ Params.InsertBefore( i, parI );
+ auto it = nbsegs.begin();
+ smIdType incr_it = i - 2 + iDiap;
+ nbsegs.insert( it + incr_it, nbSegPerDiap );
+ }
+ nbsegs[ i-2 + nbDiapason - 1 ] = nbSegPerDiap + nbTot % nbDiapason;
+ }
+
+ // transform normalized Params into real ones
+ std::vector< double > uVec( Params.Length() );
+ uVec[ 0 ] = theFirstU;
+ double abscissa;
+ for ( int i = 2; i < Params.Length(); i++ )
+ {
+ abscissa = Params( i ) * theLength;
+ tol = Min( Precision::Confusion(), 0.01 * abscissa );
+ GCPnts_AbscissaPoint APnt( tol, theC3d, abscissa, theFirstU );
+ if ( !APnt.IsDone() )
+ return error( "GCPnts_AbscissaPoint failed");
+ uVec[ i-1 ] = APnt.Parameter();
+ }
+ uVec.back() = theLastU;
+
+ // divide segments
+ double eltSize, segmentSize, par1, par2;
+ for ( int i = 0; i < (int)uVec.size()-1; i++ )
+ {
+ par1 = uVec[ i ];
+ par2 = uVec[ i+1 ];
+ smIdType nbseg = ( i < (int) nbsegs.size() ) ? nbsegs[i] : nbsegs[0];
+ if ( nbseg > 1 )
+ {
+ segmentSize = ( Params( i+2 ) - Params( i+1 )) * theLength;
+ eltSize = segmentSize / double( nbseg );
+ tol = Min( Precision::Confusion(), 0.01 * eltSize );
+ if ( !divideIntoEqualSegments( theMesh, theC3d, nbseg + 1, tol,
+ segmentSize, par1, par2, theParams ))
+ return false;
+ }
+ theParams.push_back( par2 );
+ }
+ theParams.pop_back();
+
+ return true;
+ }
+
+ case DEFLECTION:
+ {
+ GCPnts_UniformDeflection Discret( theC3d, _value[ DEFLECTION_IND ], f, l, true );
+ if ( !Discret.IsDone() )
+ return false;
+
+ int NbPoints = Discret.NbPoints();
+ for ( int i = 2; i < NbPoints; i++ )
+ {
+ double param = Discret.Parameter(i);
+ theParams.push_back( param );
+ }
+ return true;
+ }
+
+ default:;
+ }
+
+ return false;