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