0024921: ShapeAnalysis_Curve::ValidateRange doesn't adjust the range for periodic...
[occt.git] / src / ShapeAnalysis / ShapeAnalysis_Curve.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 // pdn 04.12.98 Add method using Adaptor_Curve
15 //:j8 abv 10.12.98 TR10 r0501_db.stp #9423
16 //pdn 25.12.98 private method ProjectAct
17 //szv#4 S4163
18 //:s5 abv 22.04.99 Adding debug printouts in catch {} blocks
19 //    abv 14.05.99 S4174: Adding method for exact computing of the boundary box 
20 //    gka 21.06.99 S4208: adding method NextProject(Adaptor_Curve)
21 //    msv 30.05.00 correct IsPlanar for a conic curve
22 #include <ShapeAnalysis_Curve.ixx>
23
24 #include <ElCLib.hxx>
25
26 #include <Geom2d_BoundedCurve.hxx>
27 #include <Geom2d_Line.hxx>
28 #include <Geom_BSplineCurve.hxx>
29 #include <GeomAdaptor_Curve.hxx>
30
31 #include <Precision.hxx>
32
33 #include <Standard_ErrorHandler.hxx>
34 #include <Standard_Failure.hxx>
35 #include <Adaptor3d_Curve.hxx>
36 #include <Extrema_ExtPC.hxx>
37 #include <ShapeAnalysis.hxx>
38 #include <TColgp_SequenceOfPnt.hxx>
39 #include <Geom_Line.hxx>
40 #include <Geom_Conic.hxx>
41 #include <Geom_TrimmedCurve.hxx>
42 #include <Geom_OffsetCurve.hxx>
43 #include <Geom_BezierCurve.hxx>
44 #include <ShapeExtend_ComplexCurve.hxx>
45 #include <Geom2d_Conic.hxx>
46 #include <Geom2d_TrimmedCurve.hxx>
47 #include <Geom2d_BSplineCurve.hxx>
48 #include <Geom2d_BezierCurve.hxx>
49
50 #include <Geom2d_OffsetCurve.hxx>
51 #include <Geom2dInt_Geom2dCurveTool.hxx>
52 #include <Geom2dAdaptor_Curve.hxx>
53 #include <Geom_Circle.hxx>
54 #include <Extrema_LocateExtPC.hxx>
55
56 //=======================================================================
57 //function : ProjectOnSegments
58 //purpose  : 
59 //=======================================================================
60
61 static void ProjectOnSegments (const Adaptor3d_Curve& AC, const gp_Pnt& P3D,
62                                const Standard_Integer nbseg,
63                                Standard_Real& uMin, Standard_Real& uMax,
64                                Standard_Real& distmin, gp_Pnt& proj, Standard_Real& param)
65 {
66   //  On considere <nbseg> points sur [uMin,uMax]
67   //  Quel est le plus proche. Et quel est le nouvel intervalle
68   //  (il ne peut pas deborder l ancien)
69   Standard_Real u, dist2, delta = (nbseg == 0)? 0 : (uMax-uMin)/nbseg; //szv#4:S4163:12Mar99 anti-exception
70   Standard_Real  distmin2 = distmin * distmin;
71   Standard_Boolean aHasChanged = Standard_False;
72   for (Standard_Integer i = 0; i <= nbseg; i ++) {
73     u = uMin + (delta * i);
74     gp_Pnt PU = AC.Value (u);
75     dist2 = PU.SquareDistance (P3D);
76     if (dist2 < distmin2)  {  distmin2 = dist2;  proj = PU;  param = u; aHasChanged = Standard_True;  }
77   }
78   if (aHasChanged)
79     distmin = Sqrt (distmin2);
80 #ifdef DEBUG
81   cout<<"ShapeAnalysis_Geom:Project, param="<<param<<" -> distmin="<<distmin<<endl;
82 #endif
83
84   uMax = Min (uMax, param+delta);
85   uMin = Max (uMin, param-delta);
86 }
87
88
89 //=======================================================================
90 //function : Project
91 //purpose  : 
92 //=======================================================================
93
94 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
95                                            const gp_Pnt& P3D,
96                                            const Standard_Real preci,
97                                            gp_Pnt& proj,
98                                            Standard_Real& param,
99                                            const Standard_Boolean AdjustToEnds) const
100 {
101   Standard_Real uMin = C3D->FirstParameter();
102   Standard_Real uMax = C3D->LastParameter();
103   if (uMin < uMax)  return Project (C3D,P3D,preci,proj,param,uMin,uMax,AdjustToEnds);
104   else              return Project (C3D,P3D,preci,proj,param,uMax,uMin,AdjustToEnds);
105 }
106
107 //=======================================================================
108 //function : Project
109 //purpose  : 
110 //=======================================================================
111
112 Standard_Real ShapeAnalysis_Curve::Project(const Handle(Geom_Curve)& C3D,
113                                            const gp_Pnt& P3D,
114                                            const Standard_Real preci,
115                                            gp_Pnt& proj,
116                                            Standard_Real& param,
117                                            const Standard_Real cf,
118                                            const Standard_Real cl,
119                                            const Standard_Boolean AdjustToEnds) const
120 {
121   Standard_Real distmin;
122   Standard_Real uMin = (cf < cl ? cf : cl);
123   Standard_Real uMax = (cf < cl ? cl : cf);
124   
125   if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
126     Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
127     gp_Pnt LowBound = C3D->Value(uMin);
128     gp_Pnt HigBound = C3D->Value(uMax);
129     distmin = LowBound.Distance(P3D);
130     if (distmin <= prec) {
131       param = uMin;
132       proj  = LowBound;
133       return distmin;
134     } 
135     distmin = HigBound.Distance(P3D);
136     if (distmin <= prec) {
137       param = uMax;
138       proj  = HigBound;
139       return distmin;
140     }
141   }
142
143   GeomAdaptor_Curve GAC(C3D, uMin, uMax);
144   if (!C3D->IsClosed()) {
145     //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
146     //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
147     //was (the distance between ends of the curve was a little bit more than
148     //Precision::Confusion())
149     //in that case value 0.1 was too much and this method returned not correct parameter
150     //uMin = uMin - 0.1;
151     //uMax = uMax + 0.1;
152     // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
153     Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
154     uMin -= delta;
155     uMax += delta;
156     GAC.Load(C3D, uMin, uMax);
157   }
158
159   return ProjectAct(GAC, P3D, preci, proj, param);
160 }
161
162 //=======================================================================
163 //function : Project
164 //purpose  : 
165 //=======================================================================
166
167 Standard_Real ShapeAnalysis_Curve::Project(const Adaptor3d_Curve& C3D,
168                                            const gp_Pnt& P3D,
169                                            const Standard_Real preci,
170                                            gp_Pnt& proj,
171                                            Standard_Real& param,
172                                            const Standard_Boolean AdjustToEnds) const
173
174 {
175
176   Standard_Real uMin = C3D.FirstParameter();
177   Standard_Real uMax = C3D.LastParameter();
178   
179   if (Precision::IsInfinite(uMin) && Precision::IsInfinite(uMax))
180     return ProjectAct(C3D, P3D, preci, proj, param);
181
182   Standard_Real distmin_L = Precision::Infinite(), distmin_H = Precision::Infinite();
183   Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
184   gp_Pnt LowBound = C3D.Value(uMin);
185   gp_Pnt HigBound = C3D.Value(uMax);
186   distmin_L = LowBound.Distance(P3D);
187   distmin_H = HigBound.Distance(P3D);
188
189   if (distmin_L <= prec) {
190     param = uMin;
191     proj  = LowBound;
192     return distmin_L;
193   }
194
195   if (distmin_H <= prec) {
196     param = uMax;
197     proj  = HigBound;
198     return distmin_H;
199   } 
200
201   Standard_Real distProj = ProjectAct(C3D, P3D, preci, proj, param);
202   if(  distProj < distmin_L +  Precision::Confusion() && distProj < distmin_H +  Precision::Confusion())
203     return distProj;
204
205   if( distmin_L < distmin_H)
206   {
207     param = uMin;
208     proj  = LowBound;
209     return distmin_L;
210   }
211   param = uMax;
212   proj  = HigBound;
213   return distmin_H;
214
215 }
216
217 //=======================================================================
218 //function : ProjectAct
219 //purpose  : 
220 //=======================================================================
221
222 Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& C3D,
223                                               const gp_Pnt& P3D,
224                                               const Standard_Real preci,
225                                               gp_Pnt& proj,
226                                               Standard_Real& param) const
227        
228 {
229   Standard_Boolean OK = Standard_False;
230   param = 0.;
231   try {
232     OCC_CATCH_SIGNALS
233     Extrema_ExtPC myExtPC(P3D,C3D);
234     if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) ) {
235       Standard_Real dist2, dist2Min = myExtPC.SquareDistance(1);
236       Standard_Integer index = 1;
237       for ( Standard_Integer i = 2; i <= myExtPC.NbExt(); i++) {
238         dist2 = myExtPC.SquareDistance(i);
239         if ( dist2 < dist2Min) { dist2Min = dist2; index = i; }
240       }
241       param = (myExtPC.Point(index)).Parameter();
242       proj  = (myExtPC.Point(index)).Value();
243       OK = Standard_True;
244     }
245   }
246   catch(Standard_Failure) {
247     OK = Standard_False;
248 #ifdef DEB //:s5
249     cout << "\nWarning: ShapeAnalysis_Curve::ProjectAct(): Exception in Extrema_ExtPC: "; 
250     Standard_Failure::Caught()->Print(cout); cout << endl;
251 #endif
252   }
253   
254   //szv#4:S4163:12Mar99 moved
255   Standard_Real uMin = C3D.FirstParameter(), uMax = C3D.LastParameter();
256   Standard_Boolean closed = Standard_False;  // si on franchit les bornes ...
257   Standard_Real distmin = Precision::Infinite(), valclosed = 0.;
258   Standard_Real aModParam = param;
259   Standard_Real aModMin = distmin;
260   
261   // PTV 29.05.2002 remember the old solution, cause it could be better
262   Standard_Real anOldParam =0.;
263   Standard_Boolean IsHaveOldSol = Standard_False;
264   gp_Pnt anOldProj;
265   if (OK) {
266     IsHaveOldSol = Standard_True;
267     anOldProj = proj;
268     anOldParam = param;
269     distmin = proj.Distance (P3D);
270     aModMin = distmin;
271     if (distmin > preci) OK = Standard_False;
272     // Cas TrimmedCurve a cheval. Voir la courbe de base.
273     // Si fermee, passer une periode
274     if (C3D.IsClosed()) {
275       closed = Standard_True;
276       valclosed = uMax - uMin; //szv#4:S4163:12Mar99 optimized
277     }
278   }
279
280   if (!OK) {
281     // BUG NICOLAS - Si le point est sur la courbe 0 Solutions
282     // Cela fonctionne avec ElCLib
283
284     // D une facon generale, on essaie de TOUJOURS retourner un resultat
285     //  MEME PAS BIEN BON. L appelant pourra decider alors quoi faire
286     param = 0.;
287
288     switch(C3D.GetType()) {
289     case GeomAbs_Circle:
290       {
291         const gp_Circ& aCirc = C3D.Circle();
292         proj = aCirc.Position().Location();
293         if(aCirc.Radius() <= gp::Resolution() ||
294            P3D.SquareDistance(proj) <= gp::Resolution() ) {
295           param = C3D.FirstParameter();
296           proj = proj.XYZ() + aCirc.XAxis().Direction().XYZ() * aCirc.Radius();
297         }
298         else {
299           param = ElCLib::Parameter(aCirc, P3D);
300           proj  = ElCLib::Value(param, aCirc);
301         }
302         closed = Standard_True;
303         valclosed = 2.*M_PI;
304       }
305       break;
306     case GeomAbs_Hyperbola:
307       {
308         param = ElCLib::Parameter(C3D.Hyperbola(), P3D);
309         proj  = ElCLib::Value(param, C3D.Hyperbola());
310       }
311       break;
312     case GeomAbs_Parabola:
313       {
314         param = ElCLib::Parameter(C3D.Parabola(), P3D);
315         proj  = ElCLib::Value(param, C3D.Parabola());
316       }
317       break;
318     case GeomAbs_Line:
319       {
320         param = ElCLib::Parameter(C3D.Line(), P3D);
321         proj  = ElCLib::Value(param, C3D.Line());
322       }
323       break;
324     case GeomAbs_Ellipse:
325       {
326         param = ElCLib::Parameter(C3D.Ellipse(), P3D);
327         proj  = ElCLib::Value(param, C3D.Ellipse());
328         closed = Standard_True;
329         valclosed = 2.*M_PI;
330
331       }
332       break;
333     default:
334       {
335         //  on ne va quand meme pas se laisser abattre ... ???
336         //  on tente ceci : 21 points sur la courbe, quel est le plus proche
337         distmin = Precision::Infinite();
338         ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
339         if (distmin <= preci) 
340           return distmin;
341         Extrema_LocateExtPC aProjector (P3D, C3D, param/*U0*/, uMin, uMax, preci/*TolU*/);
342         if (aProjector.IsDone())
343         {
344           param = aProjector.Point().Parameter();
345           proj = aProjector.Point().Value();
346           Standard_Real aDistNewton = P3D.Distance(proj);
347           if (aDistNewton < aModMin)
348             return aDistNewton;
349         }
350         // cout <<"newton failed"<<endl;    
351         ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
352         if (distmin <= preci) return distmin;
353         ProjectOnSegments (C3D,P3D,20,uMin,uMax,distmin,proj,param);
354         if (distmin <= preci) return distmin;
355         ProjectOnSegments (C3D,P3D,25,uMin,uMax,distmin,proj,param);
356         if (distmin <= preci) return distmin;
357         ProjectOnSegments (C3D,P3D,40,uMin,uMax,distmin,proj,param);
358         if (distmin <= preci) return distmin;
359         //  soyons raisonnable ...
360         if(distmin > aModMin) {
361           distmin = aModMin;
362           param = aModParam;
363         }
364
365         return distmin;
366       }
367     }
368   }
369   
370   //  p = PPOC.LowerDistanceParameter();  cf try
371   if ( closed && ( param < uMin || param > uMax ) ) 
372     param += ShapeAnalysis::AdjustByPeriod ( param, 0.5 * ( uMin + uMax ), valclosed );
373   
374   if (IsHaveOldSol) {
375     // PTV 29.05.2002 Compare old solution and new;
376     Standard_Real adist1, adist2;
377     adist1 = anOldProj.SquareDistance(P3D);
378     adist2 = proj.SquareDistance (P3D);
379     if (adist1 < adist2) {
380       proj = anOldProj;
381       param = anOldParam;
382     }
383   }
384   return proj.Distance (P3D);
385 }
386
387
388 //=======================================================================
389 //function : NextProject
390 //purpose  : Newton algo for projecting point on curve (S4030)
391 //=======================================================================
392
393 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
394                                                const Handle(Geom_Curve)& C3D,
395                                                const gp_Pnt& P3D,
396                                                const Standard_Real preci,
397                                                gp_Pnt& proj,
398                                                Standard_Real& param,
399                                                const Standard_Real cf,
400                                                const Standard_Real cl,
401                                                const Standard_Boolean AdjustToEnds) const
402 {
403   Standard_Real uMin = (cf < cl ? cf : cl);
404   Standard_Real uMax = (cf < cl ? cl : cf);
405   Standard_Real distmin = Precision::Infinite();
406   if (C3D->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
407     Standard_Real prec = ( AdjustToEnds ? preci : Precision::Confusion() ); //:j8 abv 10 Dec 98: tr10_r0501_db.stp #9423: protection against densing of points near one end
408     gp_Pnt LowBound = C3D->Value(uMin);
409     gp_Pnt HigBound = C3D->Value(uMax);
410     distmin = LowBound.Distance(P3D);
411     if (distmin <= prec) {
412       param = uMin;
413       proj  = LowBound;
414       return distmin;
415     } 
416     distmin = HigBound.Distance(P3D);
417     if (distmin <= prec) {
418       param = uMax;
419       proj  = HigBound;
420       return distmin;
421     }
422   }
423
424   GeomAdaptor_Curve GAC(C3D, uMin, uMax);
425   if (!C3D->IsClosed()) {
426     //modified by rln on 16/12/97 after CSR# PRO11641 entity 20767
427     //the VIso was not closed (according to C3D->IsClosed()) while it "almost"
428     //was (the distance between ends of the curve was a little bit more than
429     //Precision::Confusion())
430     //in that case value 0.1 was too much and this method returned not correct parameter
431     //uMin = uMin - 0.1;
432     //uMax = uMax + 0.1;
433     // modified by pdn on 01.07.98 after BUC60195 entity 1952 (Min() added)
434     Standard_Real delta = Min (GAC.Resolution (preci), (uMax - uMin) * 0.1);
435     uMin -= delta;
436     uMax += delta;
437     GAC.Load(C3D, uMin, uMax);
438   }
439   return NextProject ( paramPrev, GAC, P3D, preci, proj, param );
440 }
441
442 //=======================================================================
443 //function : NextProject
444 //purpose  : 
445 //=======================================================================
446
447 Standard_Real ShapeAnalysis_Curve::NextProject(const Standard_Real paramPrev,
448                                                const Adaptor3d_Curve& C3D,
449                                                const gp_Pnt& P3D,
450                                                const Standard_Real preci,
451                                                gp_Pnt& proj,
452                                                Standard_Real& param) const
453 {
454   Standard_Real uMin = C3D.FirstParameter();
455   Standard_Real uMax = C3D.LastParameter();
456   
457   Extrema_LocateExtPC aProjector (P3D, C3D, paramPrev/*U0*/, uMin, uMax, preci/*TolU*/);
458   if (aProjector.IsDone()){
459     param = aProjector.Point().Parameter();
460     proj = aProjector.Point().Value();
461     return P3D.Distance(proj);
462   }
463   return Project(C3D, P3D, preci, proj, param, Standard_False);
464 }
465
466 //=======================================================================
467 //function : AdjustParameters
468 //purpose  : Copied from StepToTopoDS_GeometricTuul::UpdateParam3d (Aug 2001)
469 //=======================================================================
470
471 Standard_Boolean ShapeAnalysis_Curve::ValidateRange (const Handle(Geom_Curve)& theCurve, 
472                                                      Standard_Real& First, Standard_Real& Last,
473                                                      const Standard_Real preci) const
474 {
475   // First et/ou Last peuvent etre en dehors des bornes naturelles de la courbe.
476   // On donnera alors la valeur en bout a First et/ou Last
477   
478   Standard_Real cf = theCurve->FirstParameter();
479   Standard_Real cl = theCurve->LastParameter();
480 //  Standard_Real preci = BRepAPI::Precision();
481
482   if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed()) {
483     if (First < cf) {
484 #ifdef DEBUG
485       cout << "Update Edge First Parameter to Curve First Parameter" << endl;
486 #endif
487       First = cf;
488     }
489     else if (First > cl) {
490 #ifdef DEBUG
491       cout << "Update Edge First Parameter to Curve Last Parameter" << endl;
492 #endif
493       First = cl;
494     }
495     if (Last < cf) {
496 #ifdef DEBUG
497       cout << "Update Edge Last Parameter to Curve First Parameter" << endl;
498 #endif
499       Last = cf;
500     }
501     else if (Last > cl) {
502 #ifdef DEBUG
503       cout << "Update Edge Last Parameter to Curve Last Parameter" << endl;
504 #endif
505       Last = cl;
506     }
507   }
508
509   // 15.11.2002 PTV OCC966
510   if (ShapeAnalysis_Curve::IsPeriodic(theCurve)) {
511     ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),First,Last); //:a7 abv 11 Feb 98: preci -> PConfusion()
512   }
513   else if (First < Last) {
514     // nothing to fix
515   }
516   else if (theCurve->IsClosed()) {
517     // l'un des points projecte se trouve sur l'origine du parametrage
518     // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
519     // DANGER precision 3d applique a une espace 1d
520     
521     // Last = cf au lieu de Last = cl
522     if      (Abs(Last - cf) < Precision::PConfusion() /*preci*/)  Last = cl ;
523     // First = cl au lieu de First = cf
524     else if (Abs(First - cl) < Precision::PConfusion() /*preci*/)  First = cf;
525
526     // on se trouve dans un cas ou l origine est traversee
527     // illegal sur une courbe fermee non periodique
528     // on inverse quand meme les parametres !!!!!!
529     else {
530       //:S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d
531       if ( theCurve->Value(First).Distance(theCurve->Value(cf)) < preci ) First = cf;
532       if ( theCurve->Value(Last).Distance(theCurve->Value(cl)) < preci ) Last = cl;
533       if ( First > Last ) {
534 #ifdef DEBUG
535         cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
536 #endif
537         Standard_Real tmp = First;
538         First = Last;
539         Last = tmp;
540       }
541     }
542   }
543   // The curve is closed within the 3D tolerance
544   else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
545     Handle(Geom_BSplineCurve) aBSpline = 
546       Handle(Geom_BSplineCurve)::DownCast(theCurve);
547     if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci ) {
548 //:S4136        <= BRepAPI::Precision()) {
549       // l'un des points projecte se trouve sur l'origine du parametrage
550       // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
551       // DANGER precision 3d applique a une espace 1d
552       
553       // Last = cf au lieu de Last = cl
554       if      (Abs(Last - cf) < Precision::PConfusion() /*preci*/) Last = cl ;
555       // First = cl au lieu de First = cf
556       else if (Abs(First - cl) < Precision::PConfusion() /*preci*/) First =  cf;
557
558       // on se trouve dans un cas ou l origine est traversee
559       // illegal sur une courbe fermee non periodique
560       // on inverse quand meme les parametres !!!!!!
561       else {
562 #ifdef DEBUG
563         cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
564 #endif
565         Standard_Real tmp = First;
566         First = Last;
567         Last = tmp;
568       }
569     }
570     //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
571     else if ( First > Last ) {
572 #ifdef DEBUG
573       cout << "Warning: parameter range is bad; curve reversed" << endl;
574 #endif
575       First = theCurve->ReversedParameter ( First );
576       Last = theCurve->ReversedParameter ( Last );
577       theCurve->Reverse();
578     }
579 //:j9 abv 11 Dec 98: PRO7747 #4875, after :j8:    else 
580     if (First == Last) {  //gka 10.07.1998 file PRO7656 entity 33334
581       First = cf; Last = cl;
582       return Standard_False;
583     }
584   }
585   else {
586 #ifdef DEBUG
587     cout << "UpdateParam3d Failed" << endl;
588     cout << "  - Curve Type : " << theCurve->DynamicType() << endl;
589     cout << "  - Param 1    : " << First << endl;
590     cout << "  - Param 2    : " << Last << endl;
591 #endif
592     //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
593     if ( First > Last ) {
594 #ifdef DEBUG
595       cout << "Warning: parameter range is bad; curve reversed" << endl;
596 #endif
597       First = theCurve->ReversedParameter ( First );
598       Last = theCurve->ReversedParameter ( Last );
599       theCurve->Reverse();
600     }
601     //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
602     if (First == Last) {
603       First -= Precision::PConfusion();
604       Last += Precision::PConfusion();
605     }
606     return Standard_False;
607   }
608   return Standard_True;
609 }
610
611 //=======================================================================
612 //function : FillBndBox
613 //purpose  : WORK-AROUND for methods brom BndLib which give not exact bounds
614 //=======================================================================
615
616 // search for extremum using Newton
617 static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d,
618                                            const Standard_Real First,
619                                            const Standard_Real Last,
620                                            const gp_Vec2d &dir,
621                                            Standard_Real &par,
622                                            gp_Pnt2d &res)
623 {
624   Standard_Real prevpar;
625   for ( Standard_Integer i=0; i <10; i++ ) {
626     prevpar = par;
627       
628     gp_Vec2d D1, D2;
629     C2d->D2 ( par, res, D1, D2 );
630     Standard_Real Det = ( D2 * dir );
631     if ( Abs ( Det ) < 1e-10 ) return Standard_True;
632     
633     par -= ( D1 * dir ) / Det;
634     if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True;
635     
636     if ( First - par >= Precision::PConfusion() || 
637          par - Last  >= Precision::PConfusion() ) return Standard_False;
638   }
639   return Standard_True;
640 }
641
642 void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d,
643                                       const Standard_Real First,
644                                       const Standard_Real Last,
645                                       const Standard_Integer NPoints,
646                                       const Standard_Boolean Exact,
647                                       Bnd_Box2d &Box) const
648 {
649   Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 );
650   Standard_Real step = ( Last - First ) / nseg;
651   for ( Standard_Integer i=0; i <= nseg; i++ ) {
652     Standard_Real par = First + i * step;
653     gp_Pnt2d pnt = C2d->Value ( par );
654     Box.Add ( pnt );
655     if ( ! Exact ) continue;
656     
657     gp_Pnt2d pextr;
658     Standard_Real parextr = par;
659     if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
660                              gp_Vec2d(1,0), parextr, pextr ) ) {
661       Box.Add ( pextr );
662     }
663     parextr = par;
664     if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
665                              gp_Vec2d(0,1), parextr, pextr ) ) {
666       Box.Add ( pextr );
667     }
668   }
669 }
670
671 //=======================================================================
672 //function : SelectForwardSeam
673 //purpose  : 
674 //=======================================================================
675
676 Standard_Integer ShapeAnalysis_Curve::SelectForwardSeam(const Handle(Geom2d_Curve)& C1,
677                                                         const Handle(Geom2d_Curve)& C2) const
678 {
679   //  SelectForward est destine a devenir un outil distinct
680   //  Il est sans doute optimisable !
681
682   Standard_Integer theCurveIndice = 0;
683
684   Handle(Geom2d_Line) L1 = Handle(Geom2d_Line)::DownCast(C1);
685   if (L1.IsNull()) {
686     // if we have BoundedCurve, create a line from C1
687     Handle(Geom2d_BoundedCurve) BC1 = Handle(Geom2d_BoundedCurve)::DownCast(C1);
688     if (BC1.IsNull()) return theCurveIndice;
689     gp_Pnt2d StartBC1 = BC1->StartPoint();
690     gp_Pnt2d EndBC1   = BC1->EndPoint();
691     gp_Vec2d VecBC1(StartBC1, EndBC1);
692     L1 = new Geom2d_Line(StartBC1, VecBC1);
693   }
694
695   Handle(Geom2d_Line) L2 = Handle(Geom2d_Line)::DownCast(C2);
696   if (L2.IsNull()) {
697     // if we have BoundedCurve, creates a line from C2
698     Handle(Geom2d_BoundedCurve) BC2 = Handle(Geom2d_BoundedCurve)::DownCast(C2);
699     if (BC2.IsNull()) return theCurveIndice;
700     gp_Pnt2d StartBC2 = BC2->StartPoint();
701     gp_Pnt2d EndBC2   = BC2->EndPoint();
702     gp_Vec2d VecBC2(StartBC2, EndBC2);
703     L2 = new Geom2d_Line(StartBC2, VecBC2);
704   }
705
706   Standard_Boolean UdirPos, UdirNeg, VdirPos, VdirNeg;
707   UdirPos = UdirNeg = VdirPos = VdirNeg = Standard_False;
708
709   gp_Dir2d theDir  = L1->Direction();
710   gp_Pnt2d theLoc1 = L1->Location();
711   gp_Pnt2d theLoc2 = L2->Location();
712
713   if        (theDir.X() > 0.) {
714     UdirPos = Standard_True; //szv#4:S4163:12Mar99 Udir unused
715   } else if (theDir.X() < 0.) {
716     UdirNeg = Standard_True; //szv#4:S4163:12Mar99 Udir unused
717   } else if (theDir.Y() > 0.) {
718     VdirPos = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
719   } else if (theDir.Y() < 0.) {
720     VdirNeg = Standard_True; //szv#4:S4163:12Mar99 Vdir unused
721   }
722   
723   if        (VdirPos) {
724     // max of Loc1.X() Loc2.X()
725     if (theLoc1.X() > theLoc2.X())   theCurveIndice  = 1;
726     else                             theCurveIndice  = 2;
727   } else if (VdirNeg) {
728     if (theLoc1.X() > theLoc2.X())   theCurveIndice  = 2;
729     else                             theCurveIndice  = 1;
730   } else if (UdirPos) {
731     // min of Loc1.X() Loc2.X()
732     if (theLoc1.Y() < theLoc2.Y())   theCurveIndice  = 1;
733     else                             theCurveIndice  = 2;
734   } else if (UdirNeg) {
735     if (theLoc1.Y() < theLoc2.Y())   theCurveIndice  = 2;
736     else                             theCurveIndice  = 1;
737   }
738
739   return theCurveIndice;
740 }
741
742 //%11 pdn 12.01.98
743 //=============================================================================
744 // Static methods for IsPlanar
745 // IsPlanar
746 //=============================================================================
747
748 static gp_XYZ GetAnyNormal ( gp_XYZ orig )
749 {
750   gp_XYZ Norm;
751   if ( Abs ( orig.Z() ) < Precision::Confusion() )
752     Norm.SetCoord ( 0, 0, 1 );
753   else {
754     Norm.SetCoord ( orig.Z(), 0, -orig.X() );
755     Standard_Real nrm = Norm.Modulus();
756     if ( nrm < Precision::Confusion() ) Norm.SetCoord ( 0, 0, 1 );
757     else Norm = Norm / nrm;
758   }
759   return Norm;
760 }
761
762 //=======================================================================
763 //function : GetSamplePoints
764 //purpose  : 
765 //=======================================================================
766 static void AppendControlPoles (TColgp_SequenceOfPnt& seq,
767                                 const Handle(Geom_Curve) curve)
768 {
769   if ( curve->IsKind(STANDARD_TYPE(Geom_Line))) {
770     seq.Append(curve->Value(0));
771     seq.Append(curve->Value(1));
772   } else if ( curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
773     seq.Append(curve->Value(0));
774     seq.Append(curve->Value(M_PI/2));
775     seq.Append(curve->Value(M_PI));
776   } else if ( curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
777     //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
778     Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
779 //     AppendControlPoles(seq,Trimmed->BasisCurve());
780     Handle(Geom_Curve) aBaseCrv = Trimmed->BasisCurve();
781     Standard_Boolean done = Standard_False;
782     if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
783       try {
784         OCC_CATCH_SIGNALS
785         Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
786         Handle(Geom_BSplineCurve) bslp = Handle(Geom_BSplineCurve)::DownCast(Ctmp);
787         bslp->Segment(curve->FirstParameter(), curve->LastParameter());
788         AppendControlPoles(seq,bslp);
789         done = Standard_True;
790       }
791       catch (Standard_Failure) {
792       }
793     }
794     else if ( aBaseCrv->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
795       try {
796         OCC_CATCH_SIGNALS
797         Handle(Geom_Geometry) Ctmp = aBaseCrv->Copy();
798         Handle(Geom_BezierCurve) bz = Handle(Geom_BezierCurve)::DownCast(Ctmp);
799         bz->Segment(curve->FirstParameter(), curve->LastParameter());
800         AppendControlPoles(seq,bz);
801         done = Standard_True;
802       }
803       catch (Standard_Failure) {
804       }
805     }
806     if (!done) {
807       seq.Append(curve->Value(curve->FirstParameter()));
808       seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
809       seq.Append(curve->Value(curve->LastParameter()));
810     }
811   } else if ( curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
812     //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
813     Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
814 //     AppendControlPoles(seq,OffsetC->BasisCurve());
815     seq.Append(curve->Value(curve->FirstParameter()));
816     seq.Append(curve->Value((curve->FirstParameter() + curve->LastParameter())/2.));
817     seq.Append(curve->Value(curve->LastParameter()));
818   } else if ( curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
819     //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
820     Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
821     TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
822     BSpline->Poles(Poles);
823     for(Standard_Integer i = 1; i <= BSpline->NbPoles(); i++)
824       seq.Append(Poles(i));
825   } else if ( curve->IsKind(STANDARD_TYPE(Geom_BezierCurve)))  {
826     //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
827     //Handle(Geom_BezierCurve) Bezier = Handle(Geom_BezierCurve)::DownCast(curve);
828     Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
829     TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
830     Bezier->Poles(Poles);
831     for(Standard_Integer i = 1; i <= Bezier->NbPoles(); i++)
832       seq.Append(Poles(i));
833   }
834 }
835
836 //%11 pdn 12.01.98
837 //szv modified
838 //=======================================================================
839 //function : IsPlanar
840 //purpose  : Detects if points lie in some plane and returns normal
841 //=======================================================================
842
843 Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const TColgp_Array1OfPnt& pnts,
844                                                 gp_XYZ& Normal,
845                                                 const Standard_Real preci)
846 {
847   Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
848   Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
849
850   if (pnts.Length() < 3) {
851     gp_XYZ N1 = pnts(1).XYZ()-pnts(2).XYZ();
852     if (noNorm) {
853       Normal = GetAnyNormal(N1);
854       return Standard_True;
855     }
856     return Abs(N1*Normal) < Precision::Confusion();
857   }
858   
859   gp_XYZ aMaxDir;
860   if (noNorm) {
861     //define a center point
862     gp_XYZ aCenter(0,0,0);
863     Standard_Integer i = 1;
864     for (; i <= pnts.Length(); i++) 
865       aCenter += pnts(i).XYZ();
866     aCenter/=pnts.Length();
867     
868     
869     aMaxDir = pnts(1).XYZ() - aCenter;
870     Normal = (pnts(pnts.Length()).XYZ() - aCenter) ^ aMaxDir;
871
872     for ( i = 1; i < pnts.Length(); i++) {
873       gp_XYZ aTmpDir = pnts(i+1).XYZ() - aCenter;
874       if(aTmpDir.SquareModulus() > aMaxDir.SquareModulus())
875         aMaxDir = aTmpDir;
876
877       gp_XYZ aDelta = (pnts(i).XYZ() - aCenter) ^ (pnts(i+1).XYZ() - aCenter);
878       if(Normal*aDelta < 0)
879         aDelta*=-1;
880       Normal += aDelta;
881     }
882   }
883
884   // check if points are linear
885   Standard_Real nrm = Normal.Modulus();
886   if ( nrm < Precision::Confusion() ) {
887     Normal = GetAnyNormal(aMaxDir);
888     return Standard_True;
889   }
890   Normal = Normal / nrm;
891
892   Standard_Real mind = RealLast(), maxd = -RealLast(), dev;
893   for (Standard_Integer i = 1; i <= pnts.Length(); i++) {
894     dev = pnts(i).XYZ() * Normal;
895     if (dev < mind) mind = dev;
896     if (dev > maxd) maxd = dev;
897   }
898
899   return ((maxd - mind) <= precision);
900 }
901
902
903 //=======================================================================
904 //function : IsPlanar
905 //purpose  : 
906 //=======================================================================
907
908  Standard_Boolean ShapeAnalysis_Curve::IsPlanar (const Handle(Geom_Curve)& curve,
909                                                  gp_XYZ& Normal,
910                                                  const Standard_Real preci)
911 {
912   Standard_Real precision = (preci > 0.0)? preci : Precision::Confusion();
913   Standard_Boolean noNorm = (Normal.SquareModulus() == 0);
914
915   if (curve->IsKind(STANDARD_TYPE(Geom_Line))) {
916     //DeclareAndCast(Geom_Line, Line, curve);
917     Handle(Geom_Line) Line = *((Handle(Geom_Line) *) &curve);
918     gp_XYZ N1 = Line->Position().Direction().XYZ();
919     if (noNorm) {
920       Normal = GetAnyNormal(N1);
921       return Standard_True;
922     }
923     return Abs(N1*Normal) < Precision::Confusion();
924   }
925
926   if (curve->IsKind(STANDARD_TYPE(Geom_Conic))) {
927     //DeclareAndCast(Geom_Conic, Conic, curve);
928     Handle(Geom_Conic) Conic = *((Handle(Geom_Conic) *) &curve);
929     gp_XYZ N1 = Conic->Axis().Direction().XYZ();
930     if (noNorm) {
931       Normal = N1;
932       return Standard_True;
933     }
934     gp_XYZ aVecMul = N1^Normal;
935     return aVecMul.SquareModulus() < Precision::SquareConfusion();
936   }
937
938   if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
939     //DeclareAndCast(Geom_TrimmedCurve, Trimmed, curve);
940     Handle(Geom_TrimmedCurve) Trimmed = *((Handle(Geom_TrimmedCurve) *) &curve);
941     return IsPlanar(Trimmed->BasisCurve(),Normal,precision);
942   }
943
944   if (curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
945     //DeclareAndCast(Geom_OffsetCurve, OffsetC, curve);
946     Handle(Geom_OffsetCurve) OffsetC = *((Handle(Geom_OffsetCurve) *) &curve);
947     return IsPlanar(OffsetC->BasisCurve(),Normal,precision);
948   }
949
950   if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
951     //DeclareAndCast(Geom_BSplineCurve, BSpline, curve);
952     Handle(Geom_BSplineCurve) BSpline = *((Handle(Geom_BSplineCurve) *) &curve);
953     TColgp_Array1OfPnt Poles(1,BSpline->NbPoles());
954     BSpline->Poles(Poles);
955     return IsPlanar(Poles,Normal,precision);
956   }
957
958   if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
959     //DeclareAndCast(Geom_BezierCurve, Bezier, curve);
960     Handle(Geom_BezierCurve) Bezier = *((Handle(Geom_BezierCurve) *) &curve);
961     TColgp_Array1OfPnt Poles(1,Bezier->NbPoles());
962     Bezier->Poles(Poles);
963     return IsPlanar(Poles,Normal,precision);
964   }
965
966   if (curve->IsKind(STANDARD_TYPE(ShapeExtend_ComplexCurve))) {
967     //DeclareAndCast(ShapeExtend_ComplexCurve, Complex, curve);
968     Handle(ShapeExtend_ComplexCurve) Complex = *((Handle(ShapeExtend_ComplexCurve) *) &curve);
969     TColgp_SequenceOfPnt sequence;
970     Standard_Integer i; // svv Jan11 2000 : porting on DEC
971     for (i = 1; i <= Complex->NbCurves(); i++)
972       AppendControlPoles(sequence,Complex->Curve(i));
973     TColgp_Array1OfPnt Poles(1,sequence.Length());
974     for (i=1; i <= sequence.Length(); i++) Poles(i) = sequence(i);
975     return IsPlanar(Poles,Normal,precision);
976   }
977
978   return Standard_False;
979 }
980
981 //=======================================================================
982 //function : GetSamplePoints
983 //purpose  : 
984 //=======================================================================
985
986 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom_Curve)& curve,
987                                                        const Standard_Real first,
988                                                        const Standard_Real last,
989                                                        TColgp_SequenceOfPnt& seq)
990 {
991   Standard_Real adelta = curve->LastParameter() - curve->FirstParameter();
992   if(!adelta )
993     return Standard_False;
994   
995   Standard_Integer aK = (Standard_Integer)ceil ((last - first) / adelta);
996   Standard_Integer nbp =100*aK;
997   if(curve->IsKind(STANDARD_TYPE(Geom_Line)))
998     nbp =2;
999   else if(curve->IsKind(STANDARD_TYPE(Geom_Circle)))
1000     nbp =360*aK;
1001   
1002   else if (curve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
1003     Handle(Geom_BSplineCurve) aBspl = Handle(Geom_BSplineCurve)::DownCast(curve);
1004     
1005     nbp = aBspl->NbKnots() * aBspl->Degree()*aK;
1006     if(nbp < 2.0) nbp=2;
1007   }
1008   else if (curve->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
1009     Handle(Geom_BezierCurve) aB = Handle(Geom_BezierCurve)::DownCast(curve);
1010     nbp = 3 + aB->NbPoles();
1011   }
1012   else if(curve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
1013     Handle(Geom_OffsetCurve) aC = Handle(Geom_OffsetCurve)::DownCast(curve);
1014     return GetSamplePoints(aC->BasisCurve(),first,last,seq);
1015   }
1016   else if(curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
1017     Handle(Geom_TrimmedCurve) aC = Handle(Geom_TrimmedCurve)::DownCast(curve);
1018     return GetSamplePoints(aC->BasisCurve(),first,last,seq);
1019   }
1020   Standard_Real step = ( last - first ) / (Standard_Real)( nbp - 1 );
1021   Standard_Real par = first, stop = last - 0.5 * step;
1022   for ( ; par < stop; par += step )
1023     seq.Append(curve->Value(par));
1024   seq.Append(curve->Value(last));
1025   return Standard_True;
1026 }
1027 //=======================================================================
1028 //function : GetSamplePoints
1029 //purpose  : 
1030 //=======================================================================
1031
1032 Standard_Boolean ShapeAnalysis_Curve::GetSamplePoints (const Handle(Geom2d_Curve)& curve,
1033                                                        const Standard_Real first,
1034                                                        const Standard_Real last,
1035                                                        TColgp_SequenceOfPnt2d& seq)
1036 {
1037   //:abv 05.06.02: TUBE.stp 
1038   // Use the same distribution of points as BRepTopAdaptor_FClass2d for consistency
1039   Geom2dAdaptor_Curve C ( curve, first, last );
1040   Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C);
1041   //-- Attention aux bsplines rationnelles de degree 3. (bouts de cercles entre autres)
1042   if (nbs > 2) nbs*=4;
1043   Standard_Real step = ( last - first ) / (Standard_Real)( nbs - 1 );
1044   Standard_Real par = first, stop = last - 0.5 * step;
1045   for ( ; par < stop; par += step )
1046     seq.Append(curve->Value(par));
1047   seq.Append(curve->Value(last));
1048   return Standard_True;
1049 /*
1050   Standard_Integer i;
1051   Standard_Real step;
1052   gp_Pnt2d Ptmp;
1053   if ( curve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
1054     seq.Append(curve->Value(first));
1055     seq.Append(curve->Value(last));
1056     return Standard_True;
1057   }
1058   else if(curve->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
1059     step = Min ( M_PI, last-first ) / 19; //:abv 05.06.02 TUBE.stp #19209...: M_PI/16
1060 //     if( step>(last-first) ) {
1061 //       seq.Append(curve->Value(first));
1062 //       seq.Append(curve->Value((last+first)/2));
1063 //       seq.Append(curve->Value(last));
1064 //       return Standard_True;
1065 //     }
1066 //     else {
1067       Standard_Real par=first;
1068       for(i=0; par<last; i++) {
1069         seq.Append(curve->Value(par));
1070         par += step;
1071       }
1072       seq.Append(curve->Value(last));
1073       return Standard_True;
1074 //     }
1075   }
1076   else if ( curve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
1077     DeclareAndCast(Geom2d_TrimmedCurve, Trimmed, curve);
1078     return GetControlPoints(Trimmed->BasisCurve(), seq, first, last);
1079   }
1080   else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
1081     DeclareAndCast(Geom2d_BSplineCurve, aBs, curve);
1082     TColStd_SequenceOfReal aSeqParam;
1083     if(!aBs.IsNull()) {
1084       aSeqParam.Append(first);
1085       for(i=1; i<=aBs->NbKnots(); i++) {
1086         if( aBs->Knot(i)>first && aBs->Knot(i)<last ) 
1087           aSeqParam.Append(aBs->Knot(i));
1088       }
1089       aSeqParam.Append(last);
1090       Standard_Integer NbPoints=aBs->Degree();
1091       if( (aSeqParam.Length()-1)*NbPoints>10 ) {
1092         for(i=1; i<aSeqParam.Length(); i++) {
1093           Standard_Real FirstPar = aSeqParam.Value(i);
1094           Standard_Real LastPar = aSeqParam.Value(i+1);
1095           step = (LastPar-FirstPar)/NbPoints;
1096           for(Standard_Integer k=0; k<NbPoints; k++ ) {
1097             aBs->D0(FirstPar+step*k, Ptmp);
1098             seq.Append(Ptmp);
1099           }
1100         }
1101         aBs->D0(last, Ptmp);
1102         seq.Append(Ptmp);
1103         return Standard_True;
1104       }
1105       else {
1106         step = (last-first)/10;
1107         for(Standard_Integer k=0; k<=10; k++ ) {
1108           aBs->D0(first+step*k, Ptmp);
1109           seq.Append(Ptmp);
1110         }
1111         return Standard_True;
1112       }
1113     }
1114   }
1115   else if ( curve->IsKind(STANDARD_TYPE(Geom2d_BezierCurve)))  {
1116     DeclareAndCast(Geom2d_BezierCurve, aBz, curve);
1117     if(!aBz.IsNull()) {
1118       Standard_Integer NbPoints=aBz->Degree();
1119       step = (last-first)/NbPoints;
1120       for(Standard_Integer k=0; k<NbPoints; k++ ) {
1121         aBz->D0(first+step*k, Ptmp);
1122         seq.Append(Ptmp);
1123       }
1124       aBz->D0(last, Ptmp);
1125       seq.Append(Ptmp);
1126       return Standard_True;
1127     }
1128   }
1129   return Standard_False;
1130 */
1131 }
1132
1133 //=======================================================================
1134 //function : IsClosed
1135 //purpose  : 
1136 //=======================================================================
1137
1138 Standard_Boolean ShapeAnalysis_Curve::IsClosed(const Handle(Geom_Curve)& theCurve,
1139                                                const Standard_Real preci)
1140 {
1141   if (theCurve->IsClosed())
1142     return Standard_True;
1143   
1144   Standard_Real prec = Max (preci, Precision::Confusion());
1145
1146   Standard_Real f, l;
1147   f = theCurve->FirstParameter();
1148   l = theCurve->LastParameter();
1149   
1150   if (Precision::IsInfinite (f) || Precision::IsInfinite (l))
1151     return Standard_False;
1152   
1153   Standard_Real aClosedVal = theCurve->Value(f).SquareDistance(theCurve->Value(l));
1154   Standard_Real preci2 = prec*prec;
1155
1156   return (aClosedVal <= preci2);
1157 }
1158 //=======================================================================
1159 //function : IsPeriodic
1160 //purpose  : OCC996
1161 //=======================================================================
1162
1163 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom_Curve)& theCurve)
1164 {
1165   // 15.11.2002 PTV OCC966
1166   // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1167   // ask IsPeriodic on BasisCurve
1168   Handle(Geom_Curve) aTmpCurve = theCurve;
1169   while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) ||
1170           (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) ) {
1171     if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
1172       aTmpCurve = Handle(Geom_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1173     if (aTmpCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
1174       aTmpCurve = Handle(Geom_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1175   }
1176   return aTmpCurve->IsPeriodic();
1177 }
1178
1179 Standard_Boolean ShapeAnalysis_Curve::IsPeriodic(const Handle(Geom2d_Curve)& theCurve)
1180 {
1181   // 15.11.2002 PTV OCC966
1182   // remove regressions in DE tests (diva, divb, divc, toe3) in KAS:dev
1183   // ask IsPeriodic on BasisCurve
1184   Handle(Geom2d_Curve) aTmpCurve = theCurve;
1185   while ( (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve))) ||
1186           (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) ) {
1187     if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1188       aTmpCurve = Handle(Geom2d_OffsetCurve)::DownCast(aTmpCurve)->BasisCurve();
1189     if (aTmpCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1190       aTmpCurve = Handle(Geom2d_TrimmedCurve)::DownCast(aTmpCurve)->BasisCurve();
1191   }
1192   return aTmpCurve->IsPeriodic();
1193 }