1 // Created on: 1996-11-08
2 // Created by: Jean Claude VAUTHIER
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <GCPnts_DeflectionType.hxx>
18 #include <Standard_ConstructionError.hxx>
19 #include <Precision.hxx>
24 #include <NCollection_List.hxx>
25 #include <math_PSO.hxx>
26 #include <math_BrentMinimum.hxx>
28 #define Us3 0.3333333333333333333333333333
30 void GCPnts_TangentialDeflection::EvaluateDu (
32 const Standard_Real U,
35 Standard_Boolean& NotDone) const {
39 Standard_Real Lt = T.Magnitude ();
40 Standard_Real LTol = Precision::Confusion ();
41 if (Lt > LTol && N.Magnitude () > LTol) {
42 Standard_Real Lc = N.CrossMagnitude (T);
43 Standard_Real Ln = Lc/Lt;
45 Du = sqrt (8.0 * Max(curvatureDeflection, myMinLen) / Ln);
46 NotDone = Standard_False;
52 //=======================================================================
53 //function : GCPnts_TangentialDeflection
55 //=======================================================================
57 GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (
59 const Standard_Real AngularDeflection,
60 const Standard_Real CurvatureDeflection,
61 const Standard_Integer MinimumOfPoints,
62 const Standard_Real UTol,
63 const Standard_Real theMinLen)
66 Initialize (C,AngularDeflection,CurvatureDeflection,MinimumOfPoints,UTol,theMinLen);
70 //=======================================================================
71 //function : GCPnts_TangentialDeflection
73 //=======================================================================
75 GCPnts_TangentialDeflection::GCPnts_TangentialDeflection (
77 const Standard_Real FirstParameter,
78 const Standard_Real LastParameter,
79 const Standard_Real AngularDeflection,
80 const Standard_Real CurvatureDeflection,
81 const Standard_Integer MinimumOfPoints,
82 const Standard_Real UTol,
83 const Standard_Real theMinLen)
97 //=======================================================================
98 //function : Initialize
100 //=======================================================================
102 void GCPnts_TangentialDeflection::Initialize (
104 const Standard_Real AngularDeflection,
105 const Standard_Real CurvatureDeflection,
106 const Standard_Integer MinimumOfPoints,
107 const Standard_Real UTol,
108 const Standard_Real theMinLen)
121 //=======================================================================
122 //function : Initialize
124 //=======================================================================
126 void GCPnts_TangentialDeflection::Initialize (
128 const Standard_Real FirstParameter,
129 const Standard_Real LastParameter,
130 const Standard_Real AngularDeflection,
131 const Standard_Real CurvatureDeflection,
132 const Standard_Integer MinimumOfPoints,
133 const Standard_Real UTol,
134 const Standard_Real theMinLen)
138 Standard_ConstructionError_Raise_if (CurvatureDeflection < Precision::Confusion () ||
139 AngularDeflection < Precision::Angular (),
140 "GCPnts_TangentialDeflection::Initialize - Zero Deflection")
144 if (FirstParameter < LastParameter) {
145 firstu = FirstParameter;
146 lastu = LastParameter;
149 lastu = FirstParameter;
150 firstu = LastParameter;
153 angularDeflection = AngularDeflection;
154 curvatureDeflection = CurvatureDeflection;
155 minNbPnts = Max (MinimumOfPoints, 2);
156 myMinLen = Max(theMinLen, Precision::Confusion());
158 switch (C.GetType()) {
168 case GeomAbs_BSplineCurve:
170 Handle_TheBSplineCurve BS = C.BSpline() ;
171 if (BS->NbPoles() == 2 ) PerformLinear (C);
172 else PerformCurve (C);
175 case GeomAbs_BezierCurve:
177 Handle_TheBezierCurve BZ = C.Bezier();
178 if (BZ->NbPoles() == 2) PerformLinear (C);
179 else PerformCurve (C);
182 default: PerformCurve (C);
188 //=======================================================================
189 //function : PerformLinear
191 //=======================================================================
193 void GCPnts_TangentialDeflection::PerformLinear (const TheCurve& C) {
197 parameters.Append (firstu);
201 Standard_Real Du = (lastu - firstu) / minNbPnts;
202 Standard_Real U = firstu + Du;
203 for (Standard_Integer i = 2; i < minNbPnts; i++)
206 parameters.Append (U);
212 parameters.Append (lastu);
216 //=======================================================================
217 //function : PerformCircular
219 //=======================================================================
221 void GCPnts_TangentialDeflection::PerformCircular (const TheCurve& C)
223 // akm 8/01/02 : check the radius before divide by it
224 Standard_Real dfR = C.Circle().Radius();
225 Standard_Real Du = GCPnts_TangentialDeflection::ArcAngularStep(
226 dfR, curvatureDeflection, angularDeflection, myMinLen);
228 const Standard_Real aDiff = lastu - firstu;
229 // Round up number of points to satisfy curvatureDeflection more precisely
230 Standard_Integer NbPoints = (Standard_Integer)Min(Ceiling(aDiff / Du), 1.0e+6);
231 NbPoints = Max(NbPoints, minNbPnts - 1);
232 Du = aDiff / NbPoints;
235 Standard_Real U = firstu;
236 for (Standard_Integer i = 1; i <= NbPoints; i++)
239 parameters.Append (U);
244 parameters.Append (lastu);
249 //=======================================================================
250 //function : PerformCurve
251 //purpose : On respecte ll'angle et la fleche, on peut imposer un nombre
252 // minimum de points sur un element lineaire
253 //=======================================================================
254 void GCPnts_TangentialDeflection::PerformCurve (const TheCurve& C)
257 Standard_Integer i, j;
259 gp_Pnt MiddlePoint, CurrentPoint, LastPoint;
260 Standard_Real Du, Dusave, MiddleU, L1, L2;
262 Standard_Real U1 = firstu;
263 Standard_Real LTol = Precision::Confusion (); //protection longueur nulle
264 Standard_Real ATol = 1.e-2 * angularDeflection;
267 else if(ATol < 1.e-7)
270 D0 (C, lastu, LastPoint);
272 //Initialization du calcul
274 Standard_Boolean NotDone = Standard_True;
275 Dusave = (lastu - firstu)*Us3;
277 EvaluateDu (C, U1, CurrentPoint, Du, NotDone);
278 parameters.Append (U1);
279 points .Append (CurrentPoint);
281 // Used to detect "isLine" current bspline and in Du computation in general handling.
282 Standard_Integer NbInterv = C.NbIntervals(GeomAbs_CN);
283 TColStd_Array1OfReal Intervs(1, NbInterv+1);
284 C.Intervals(Intervs, GeomAbs_CN);
286 if (NotDone || Du > 5. * Dusave) {
287 //C'est soit une droite, soit une singularite :
288 V1 = (LastPoint.XYZ() - CurrentPoint.XYZ());
292 //Si c'est une droite on verifie en calculant minNbPoints :
293 Standard_Boolean IsLine = Standard_True;
294 Standard_Integer NbPoints = (minNbPnts > 3) ? minNbPnts : 3;
295 switch (C.GetType()) {
296 case GeomAbs_BSplineCurve:
298 Handle_TheBSplineCurve BS = C.BSpline() ;
299 NbPoints = Max(BS->Degree() + 1, NbPoints);
302 case GeomAbs_BezierCurve:
304 Handle_TheBezierCurve BZ = C.Bezier();
305 NbPoints = Max(BZ->Degree() + 1, NbPoints);
311 Standard_Real param = 0.;
312 for (i = 1; i <= NbInterv && IsLine; ++i)
314 // Avoid usage intervals out of [firstu, lastu].
315 if ((Intervs(i+1) < firstu) ||
316 (Intervs(i) > lastu))
320 // Fix border points in applicable intervals, to avoid be out of target interval.
321 if ((Intervs(i) < firstu) &&
322 (Intervs(i+1) > firstu))
326 if ((Intervs(i) < lastu) &&
327 (Intervs(i+1) > lastu))
329 Intervs(i + 1) = lastu;
332 Standard_Real delta = (Intervs(i+1) - Intervs(i))/NbPoints;
333 for (j = 1; j <= NbPoints && IsLine; ++j)
335 param = Intervs(i) + j*delta;
336 D0 (C, param, MiddlePoint);
337 V2 = (MiddlePoint.XYZ() - CurrentPoint.XYZ());
341 const Standard_Real aAngle = V2.CrossMagnitude(V1)/(L1*L2);
342 IsLine = (aAngle < ATol);
357 //c'etait une singularite on continue :
359 EvaluateDu (C, param, MiddlePoint, Du, NotDone);
364 Du = (lastu-firstu)/2.1;
365 MiddleU = firstu + Du;
366 D0 (C, MiddleU, MiddlePoint);
367 V1 = (MiddlePoint.XYZ() - CurrentPoint.XYZ());
371 // L1 < LTol C'est une courbe de longueur nulle, calcul termine :
372 // on renvoi un segment de 2 points (protection)
373 parameters.Append (lastu);
374 points .Append (LastPoint);
380 if (Du > Dusave) Du = Dusave;
386 parameters.Append (lastu);
387 points .Append (LastPoint);
392 //Traitement normal pour une courbe
393 Standard_Boolean MorePoints = Standard_True;
394 Standard_Real U2 = firstu;
395 Standard_Real AngleMax = angularDeflection * 0.5; //car on prend le point milieu
396 Standard_Integer aIdx[2] = {Intervs.Lower(), Intervs.Lower()}; // Indexes of intervals of U1 and U2, used to handle non-uniform case.
397 Standard_Boolean isNeedToCheck = Standard_False;
398 gp_Pnt aPrevPoint = points.Last();
401 aIdx[0] = getIntervalIdx(U1, Intervs, aIdx[0]);
404 if (U2 >= lastu) { //Bout de courbe
406 CurrentPoint = LastPoint;
410 else D0 (C, U2, CurrentPoint); //Point suivant
412 Standard_Real Coef = 0.0, ACoef = 0., FCoef = 0.;
413 Standard_Boolean Correction, TooLarge, TooSmall;
414 TooLarge = Standard_False;
415 Correction = Standard_True;
416 TooSmall = Standard_False;
418 while (Correction) { //Ajustement Du
421 aIdx[1] = getIntervalIdx(U2, Intervs, aIdx[0]);
422 if (aIdx[1] > aIdx[0]) // Jump to another polynom.
424 if (Du > (Intervs(aIdx[0] + 1) - Intervs(aIdx[0]) ) * Us3) // Set Du to the smallest value and check deflection on it.
426 Du = (Intervs(aIdx[0] + 1) - Intervs(aIdx[0]) ) * Us3;
430 D0 (C, U2, CurrentPoint);
434 MiddleU = (U1+U2)*0.5; //Verif / au point milieu
435 D0 (C, MiddleU, MiddlePoint);
437 V1 = (CurrentPoint.XYZ() - aPrevPoint.XYZ()); //Critere de fleche
438 V2 = (MiddlePoint.XYZ() - aPrevPoint.XYZ());
441 FCoef = (L1 > myMinLen) ?
442 V1.CrossMagnitude(V2)/(L1*curvatureDeflection) : 0.0;
444 V1 = (CurrentPoint.XYZ() - MiddlePoint.XYZ()); //Critere d'angle
447 if (L1 > myMinLen && L2 > myMinLen)
449 Standard_Real angg = V1.CrossMagnitude(V2) / (L1 * L2);
450 ACoef = angg / AngleMax;
455 //On retient le plus penalisant
456 Coef = Max(ACoef, FCoef);
458 if (isNeedToCheck && Coef < 0.55)
460 isNeedToCheck = Standard_False;
465 D0 (C, U2, CurrentPoint);
470 if (Abs (lastu-U2) < uTol) {
471 parameters.Append (lastu);
472 points .Append (LastPoint);
473 MorePoints = Standard_False;
474 Correction = Standard_False;
477 if (Coef >= 0.55 || TooLarge) {
478 parameters.Append (U2);
479 points .Append (CurrentPoint);
480 aPrevPoint = CurrentPoint;
481 Correction = Standard_False;
482 isNeedToCheck = Standard_True;
485 Correction = Standard_False;
486 aPrevPoint = CurrentPoint;
489 TooSmall = Standard_True;
490 //Standard_Real UUU2 = U2;
491 Du += Min((U2-U1)*(1.-Coef), Du*Us3);
496 D0 (C, U2, CurrentPoint);
503 if (!aPrevPoint.IsEqual(points.Last(), Precision::Confusion()))
505 parameters.Append (U1);
506 points .Append (aPrevPoint);
510 CurrentPoint = MiddlePoint;
515 D0 (C, U2, CurrentPoint);
516 TooLarge = Standard_True;
527 //La fleche est critere de decoupage
528 EvaluateDu (C, U2, CurrentPoint, Du, NotDone);
530 Du += (Du-Dusave)*(Du/Dusave);
531 if (Du > 1.5 * Dusave) Du = 1.5 * Dusave;
532 if (Du < 0.75* Dusave) Du = 0.75 * Dusave;
536 //L'angle est le critere de decoupage
537 Du += (Du-Dusave)*(Du/Dusave);
538 if (Du > 1.5 * Dusave) Du = 1.5 * Dusave;
539 if (Du < 0.75* Dusave) Du = 0.75 * Dusave;
546 parameters.Append (lastu);
547 points .Append (LastPoint);
548 MorePoints = Standard_False;
550 else if (Du*Us3 > uTol) Du*=Us3;
556 //Recalage avant dernier point :
557 i = points.Length()-1;
558 // Real d = points (i).Distance (points (i+1));
559 // if (Abs(parameters (i) - parameters (i+1))<= 0.000001 || d < Precision::Confusion()) {
560 // cout<<"deux points confondus"<<endl;
561 // parameters.Remove (i+1);
562 // points.Remove (i+1);
566 MiddleU = parameters (i-1);
567 MiddleU = (lastu + MiddleU)*0.5;
568 D0 (C, MiddleU, MiddlePoint);
569 parameters.SetValue (i, MiddleU);
570 points .SetValue (i, MiddlePoint);
573 //-- On rajoute des points aux milieux des segments si le nombre
574 //-- mini de points n'est pas atteint
576 Standard_Integer Nbp = points.Length();
578 //std::cout << "GCPnts_TangentialDeflection: Number of Points (" << Nbp << " " << minNbPnts << " )" << std::endl;
580 while(Nbp < minNbPnts)
582 for (i = 2; i <= Nbp; i += 2)
584 MiddleU = (parameters.Value(i-1)+parameters.Value(i))*0.5;
585 D0 (C, MiddleU, MiddlePoint);
586 parameters.InsertBefore(i,MiddleU);
587 points.InsertBefore(i,MiddlePoint);
591 //Additional check for intervals
592 Standard_Real MinLen2 = myMinLen * myMinLen;
593 Standard_Integer MaxNbp = 10 * Nbp;
594 for(i = 1; i < Nbp; ++i)
597 U2 = parameters(i + 1);
604 // Check maximal deflection on interval;
605 Standard_Real dmax = 0.;
606 Standard_Real umax = 0.;
607 Standard_Real amax = 0.;
608 EstimDefl(C, U1, U2, dmax, umax);
609 const gp_Pnt& P1 = points(i);
610 const gp_Pnt& P2 = points(i+1);
611 D0(C, umax, MiddlePoint);
612 amax = EstimAngl(P1, MiddlePoint, P2);
613 if(dmax > curvatureDeflection || amax > AngleMax)
615 if(umax - U1 > uTol && U2 - umax > uTol)
617 if (P1.SquareDistance(MiddlePoint) > MinLen2 && P2.SquareDistance(MiddlePoint) > MinLen2)
619 parameters.InsertAfter(i, umax);
620 points.InsertAfter(i, MiddlePoint);
622 --i; //To compensate ++i in loop header: i must point to first part of splitted interval
634 //=======================================================================
635 //function : EstimDefl
636 //purpose : Estimation of maximal deflection for interval [U1, U2]
638 //=======================================================================
639 void GCPnts_TangentialDeflection::EstimDefl (const TheCurve& C,
640 const Standard_Real U1, const Standard_Real U2,
641 Standard_Real& MaxDefl, Standard_Real& UMax)
643 Standard_Real Du = (lastu - firstu);
645 TheMaxCurvLinDist aFunc(C, U1, U2);
647 const Standard_Integer aNbIter = 100;
648 Standard_Real reltol = Max(1.e-3, 2.*uTol/((Abs(U1) + Abs(U2))));
650 math_BrentMinimum anOptLoc(reltol, aNbIter, uTol);
651 anOptLoc.Perform(aFunc, U1, (U1+U2)/2., U2);
652 if(anOptLoc.IsDone())
654 MaxDefl = Sqrt(-anOptLoc.Minimum());
655 UMax = anOptLoc.Location();
659 math_Vector aLowBorder(1,1);
660 math_Vector aUppBorder(1,1);
661 math_Vector aSteps(1,1);
663 aSteps(1) = Max(0.1 * Du, 100. * uTol);
664 Standard_Integer aNbParticles = Max(8, RealToInt(32 * (U2 - U1) / Du));
670 Standard_Real aValue;
672 TheMaxCurvLinDistMV aFuncMV(aFunc);
674 math_PSO aFinder(&aFuncMV, aLowBorder, aUppBorder, aSteps, aNbParticles);
675 aFinder.Perform(aSteps, aValue, aT);
677 anOptLoc.Perform(aFunc, Max(aT(1) - aSteps(1), U1) , aT(1), Min(aT(1) + aSteps(1),U2));
678 if(anOptLoc.IsDone())
680 MaxDefl = Sqrt(-anOptLoc.Minimum());
681 UMax = anOptLoc.Location();
684 MaxDefl = Sqrt(-aValue);