0032295: Coding Rules - merge GCPnts_AbscissaPoint.pxx into GCPnts_AbscissaPoint.cxx
[occt.git] / src / GCPnts / GCPnts_AbscissaPoint.cxx
1 // Created on: 1995-05-05
2 // Created by: Modelistation
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <GCPnts_AbscissaPoint.hxx>
18
19 #include <GCPnts_AbscissaType.hxx>
20 #include <GCPnts_TCurveTypes.hxx>
21 #include <Standard_ConstructionError.hxx>
22
23 //! Dimension independent used to implement GCPnts_AbscissaPoint
24 //! compute the type  and the length ratio if GCPnts_LengthParametrized.
25 template<class TheCurve>
26 static GCPnts_AbscissaType computeType (const TheCurve& theC,
27                                         Standard_Real& theRatio)
28 {
29   if (theC.NbIntervals (GeomAbs_CN) > 1)
30   {
31     return GCPnts_AbsComposite;
32   }
33
34   switch (theC.GetType())
35   {
36     case GeomAbs_Line:
37     {
38       theRatio = 1.0;
39       return GCPnts_LengthParametrized;
40     }
41     case GeomAbs_Circle:
42     {
43       theRatio = theC.Circle().Radius();
44       return GCPnts_LengthParametrized;
45     }
46     case GeomAbs_BezierCurve:
47     {
48       Handle(typename GCPnts_TCurveTypes<TheCurve>::BezierCurve) aBz = theC.Bezier();
49       if (aBz->NbPoles() == 2
50       && !aBz->IsRational())
51       {
52         theRatio = aBz->DN (0, 1).Magnitude();
53         return GCPnts_LengthParametrized;
54       }
55       return GCPnts_Parametrized;
56     }
57     case GeomAbs_BSplineCurve:
58     {
59       Handle(typename GCPnts_TCurveTypes<TheCurve>::BSplineCurve) aBs = theC.BSpline();
60       if (aBs->NbPoles() == 2
61       && !aBs->IsRational())
62       {
63         theRatio = aBs->DN (aBs->FirstParameter(), 1).Magnitude();
64         return GCPnts_LengthParametrized;
65       }
66       return GCPnts_Parametrized;
67     }
68     default:
69     {
70       return GCPnts_Parametrized;
71     }
72   }
73 }
74
75 //! Compute a point at distance theAbscis from parameter theU0 using theUi as initial guess
76 template<class TheCurve>
77 static void Compute (CPnts_AbscissaPoint& theComputer,
78                      const TheCurve& theC,
79                      Standard_Real& theAbscis,
80                      Standard_Real& theU0,
81                      Standard_Real& theUi,
82                      const Standard_Real theEPSILON)
83 {
84   // test for easy solution
85   if (Abs (theAbscis) <= Precision::Confusion())
86   {
87     theComputer.SetParameter (theU0);
88     return;
89   }
90
91   Standard_Real aRatio = 1.0;
92   const GCPnts_AbscissaType aType = computeType (theC, aRatio);
93   switch (aType)
94   {
95     case GCPnts_LengthParametrized:
96     {
97       theComputer.SetParameter (theU0 + theAbscis / aRatio);
98       return;
99     }
100     case GCPnts_Parametrized:
101     {
102       theComputer.Init (theC);
103       theComputer.Perform (theAbscis, theU0, theUi, theEPSILON);
104       return;
105     }
106     case GCPnts_AbsComposite:
107     {
108       const Standard_Integer aNbIntervals = theC.NbIntervals (GeomAbs_CN);
109       TColStd_Array1OfReal aTI (1, aNbIntervals + 1);
110       theC.Intervals (aTI, GeomAbs_CN);
111       Standard_Real aL = 0.0, aSign = 1.0;
112       Standard_Integer anIndex = 1;
113       BSplCLib::Hunt (aTI, theU0, anIndex);
114       Standard_Integer aDirection = 1;
115       if (theAbscis < 0)
116       {
117         aDirection = 0;
118         theAbscis = -theAbscis;
119         aSign = -1.0;
120       }
121
122       while (anIndex >= 1
123           && anIndex <= aNbIntervals)
124       {
125         aL = CPnts_AbscissaPoint::Length (theC, theU0, aTI (anIndex + aDirection));
126         if (Abs (aL - theAbscis) <= Precision::Confusion())
127         {
128           theComputer.SetParameter (aTI (anIndex + aDirection));
129           return;
130         }
131
132         if (aL > theAbscis)
133         {
134           if (theUi < aTI (anIndex)
135            || theUi > aTI (anIndex + 1))
136           {
137             theUi = (theAbscis / aL) * (aTI (anIndex + 1) - theU0);
138             if (aDirection)
139             {
140               theUi = theU0 + theUi;
141             }
142             else
143             {
144               theUi = theU0 - theUi;
145             }
146           }
147           theComputer.Init (theC, aTI (anIndex), aTI (anIndex + 1));
148           theComputer.Perform (aSign * theAbscis, theU0, theUi, theEPSILON);
149           return;
150         }
151         else
152         {
153           theU0 = aTI (anIndex + aDirection);
154           theAbscis -= aL;
155         }
156         if (aDirection)
157         {
158           ++anIndex;
159         }
160         else
161         {
162           --anIndex;
163         }
164       }
165
166       // Push a little bit outside the limits (hairy !!!)
167       theUi = theU0 + 0.1;
168       theComputer.Init (theC, theU0, theU0 + 0.2);
169       theComputer.Perform (aSign * theAbscis, theU0, theUi, theEPSILON);
170       return;
171     }
172     break;
173   }
174 }
175
176 //! Introduced by rbv for curvilinear parametrization
177 //! performs more appropriate tolerance management.
178 template<class TheCurve>
179 static void AdvCompute (CPnts_AbscissaPoint& theComputer,
180                         const TheCurve& theC,
181                         Standard_Real& theAbscis,
182                         Standard_Real& theU0,
183                         Standard_Real& theUi,
184                         const Standard_Real theEPSILON)
185 {
186   Standard_Real aRatio = 1.0;
187   const GCPnts_AbscissaType aType = computeType (theC, aRatio);
188   switch (aType)
189   {
190     case GCPnts_LengthParametrized:
191     {
192       theComputer.SetParameter (theU0 + theAbscis / aRatio);
193       return;
194     }
195     case GCPnts_Parametrized:
196     {
197       // theComputer.Init (theC);
198       theComputer.Init (theC, theEPSILON); //rbv's modification
199       theComputer.AdvPerform (theAbscis, theU0, theUi, theEPSILON);
200       return;
201     }
202     case GCPnts_AbsComposite:
203     {
204       const Standard_Integer aNbIntervals = theC.NbIntervals (GeomAbs_CN);
205       TColStd_Array1OfReal aTI (1, aNbIntervals + 1);
206       theC.Intervals (aTI, GeomAbs_CN);
207       Standard_Real aL = 0.0, aSign = 1.0;
208       Standard_Integer anIndex = 1;
209       BSplCLib::Hunt (aTI, theU0, anIndex);
210
211       Standard_Integer aDirection = 1;
212       if (theAbscis < 0)
213       {
214         aDirection = 0;
215         theAbscis = -theAbscis;
216         aSign = -1.0;
217       }
218
219       if (anIndex == 0 && aDirection > 0)
220       {
221         aL = CPnts_AbscissaPoint::Length (theC, theU0, aTI (anIndex + aDirection), theEPSILON);
222         if (Abs (aL - theAbscis) <= /*Precision::Confusion()*/theEPSILON)
223         {
224           theComputer.SetParameter (aTI (anIndex + aDirection));
225           return;
226         }
227
228         if (aL > theAbscis)
229         {
230           if (theUi > aTI (anIndex + 1))
231           {
232             theUi = (theAbscis / aL) * (aTI (anIndex + 1) - theU0);
233             theUi = theU0 + theUi;
234           }
235           theComputer.Init (theC, theU0, aTI (anIndex + 1), theEPSILON);
236           theComputer.AdvPerform (aSign * theAbscis, theU0, theUi, theEPSILON);
237           return;
238         }
239         else
240         {
241           theU0 = aTI (anIndex + aDirection);
242           theAbscis -= aL;
243         }
244         ++anIndex;
245       }
246
247       while (anIndex >= 1
248           && anIndex <= aNbIntervals)
249       {
250         aL = CPnts_AbscissaPoint::Length (theC, theU0, aTI (anIndex + aDirection), theEPSILON);
251         if (Abs (aL - theAbscis) <= Precision::PConfusion())
252         {
253           theComputer.SetParameter (aTI (anIndex + aDirection));
254           return;
255         }
256
257         if (aL > theAbscis)
258         {
259           if (theUi < aTI (anIndex)
260            || theUi > aTI (anIndex + 1))
261           {
262             theUi = (theAbscis / aL) * (aTI (anIndex + 1) - theU0);
263             if (aDirection)
264             {
265               theUi = theU0 + theUi;
266             }
267             else
268             {
269               theUi = theU0 - theUi;
270             }
271           }
272           theComputer.Init (theC, aTI (anIndex), aTI (anIndex + 1), theEPSILON);
273           theComputer.AdvPerform (aSign * theAbscis, theU0, theUi, theEPSILON);
274           return;
275         }
276         else
277         {
278           theU0 = aTI (anIndex + aDirection);
279           theAbscis -= aL;
280         }
281         if (aDirection)
282         {
283           ++anIndex;
284         }
285         else
286         {
287           --anIndex;
288         }
289       }
290
291       // Push a little bit outside the limits (hairy !!!)
292       const Standard_Boolean isNonPeriodic = !theC.IsPeriodic();
293       theUi = theU0 + aSign * 0.1;
294       Standard_Real aU1 = theU0 + aSign * 0.2;
295       if (isNonPeriodic)
296       {
297         if (aSign > 0)
298         {
299           theUi = Min (theUi, theC.LastParameter());
300           aU1   = Min (aU1,   theC.LastParameter());
301         }
302         else
303         {
304           theUi = Max (theUi, theC.FirstParameter());
305           aU1   = Max (aU1,   theC.FirstParameter());
306         }
307       }
308
309       theComputer.Init (theC, theU0, aU1, theEPSILON);
310       theComputer.AdvPerform (aSign * theAbscis, theU0, theUi, theEPSILON);
311       return;
312     }
313     break;
314   }
315 }
316
317 //=======================================================================
318 //function : GCPnts_AbscissaPoint
319 //purpose  :
320 //=======================================================================
321 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint() 
322 {
323   //
324 }
325
326 //=======================================================================
327 //function : Length
328 //purpose  :
329 //=======================================================================
330 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor3d_Curve& theC)
331 {
332   return GCPnts_AbscissaPoint::Length (theC, theC.FirstParameter(), theC.LastParameter());
333 }
334
335 //=======================================================================
336 //function : Length
337 //purpose  :
338 //=======================================================================
339 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor2d_Curve2d& theC)
340 {
341   return GCPnts_AbscissaPoint::Length (theC, theC.FirstParameter(), theC.LastParameter());
342 }
343
344 //=======================================================================
345 //function : Length
346 //purpose  :
347 //=======================================================================
348 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor3d_Curve& theC,
349                                             const Standard_Real theTol)
350 {
351   return GCPnts_AbscissaPoint::Length (theC, theC.FirstParameter(), theC.LastParameter(), theTol);
352 }
353
354 //=======================================================================
355 //function : Length
356 //purpose  :
357 //=======================================================================
358 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor2d_Curve2d& theC,
359                                             const Standard_Real theTol)
360 {
361   return GCPnts_AbscissaPoint::Length (theC, theC.FirstParameter(), theC.LastParameter(), theTol);
362 }
363
364 //=======================================================================
365 //function : Length
366 //purpose  :
367 //=======================================================================
368 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor3d_Curve& theC,
369                                             const Standard_Real theU1, const Standard_Real theU2)
370 {
371   return length (theC, theU1, theU2, NULL);
372 }
373
374 //=======================================================================
375 //function : Length
376 //purpose  :
377 //=======================================================================
378 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor2d_Curve2d& theC,
379                                             const Standard_Real theU1, const Standard_Real theU2)
380 {
381   return length (theC, theU1, theU2, NULL);
382 }
383
384 //=======================================================================
385 //function : Length
386 //purpose  :
387 //=======================================================================
388 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor3d_Curve& theC,
389                                             const Standard_Real theU1, const Standard_Real theU2,
390                                             const Standard_Real theTol)
391 {
392   return length (theC, theU1, theU2, &theTol);
393 }
394
395 //=======================================================================
396 //function : Length
397 //purpose  :
398 //=======================================================================
399 Standard_Real GCPnts_AbscissaPoint::Length (const Adaptor2d_Curve2d& theC,
400                                             const Standard_Real theU1, const Standard_Real theU2,
401                                             const Standard_Real theTol)
402 {
403   return length (theC, theU1, theU2, &theTol);
404 }
405
406 //=======================================================================
407 //function : length
408 //purpose  :
409 //=======================================================================
410 template<class TheCurve>
411 Standard_Real GCPnts_AbscissaPoint::length (const TheCurve& theC,
412                                             const Standard_Real theU1, const Standard_Real theU2,
413                                             const Standard_Real* theTol)
414 {
415   Standard_Real aRatio = 1.0;
416   const GCPnts_AbscissaType aType = computeType (theC, aRatio);
417   switch (aType)
418   {
419     case GCPnts_LengthParametrized:
420     {
421       return Abs (theU2 - theU1) * aRatio;
422     }
423     case GCPnts_Parametrized:
424     {
425       return theTol != NULL
426            ? CPnts_AbscissaPoint::Length (theC, theU1, theU2, *theTol)
427            : CPnts_AbscissaPoint::Length (theC, theU1, theU2);
428     }
429     case GCPnts_AbsComposite:
430     {
431       const Standard_Integer aNbIntervals = theC.NbIntervals (GeomAbs_CN);
432       TColStd_Array1OfReal aTI (1, aNbIntervals + 1);
433       theC.Intervals (aTI, GeomAbs_CN);
434       const Standard_Real aUU1 = Min (theU1, theU2);
435       const Standard_Real aUU2 = Max (theU1, theU2);
436       Standard_Real aL = 0.0;
437       for (Standard_Integer anIndex = 1; anIndex <= aNbIntervals; ++anIndex)
438       {
439         if (aTI (anIndex)     > aUU2) { break; }
440         if (aTI (anIndex + 1) < aUU1) { continue; }
441         if (theTol != NULL)
442         {
443           aL += CPnts_AbscissaPoint::Length (theC,
444                                              Max (aTI (anIndex),     aUU1),
445                                              Min (aTI (anIndex + 1), aUU2),
446                                              *theTol);
447         }
448         else
449         {
450           aL += CPnts_AbscissaPoint::Length (theC,
451                                              Max (aTI (anIndex),     aUU1),
452                                              Min (aTI (anIndex + 1), aUU2));
453         }
454       }
455       return aL;
456     }
457   }
458   return RealLast();
459 }
460
461 //=======================================================================
462 //function : compute
463 //purpose  :
464 //=======================================================================
465 template<class TheCurve>
466 void GCPnts_AbscissaPoint::compute (const TheCurve& theC,
467                                     const Standard_Real theAbscissa,
468                                     const Standard_Real theU0)
469 {
470   const Standard_Real aL = GCPnts_AbscissaPoint::Length (theC);
471   if (aL < Precision::Confusion())
472   {
473     throw Standard_ConstructionError();
474   }
475
476   Standard_Real anAbscis = theAbscissa;
477   Standard_Real aUU0 = theU0;
478   Standard_Real aUUi = theU0 + (anAbscis / aL) * (theC.LastParameter() - theC.FirstParameter());
479   Compute (myComputer, theC, anAbscis, aUU0, aUUi,
480            theC.Resolution (Precision::Confusion()));
481 }
482
483 //=======================================================================
484 //function : GCPnts_AbscissaPoint
485 //purpose  :
486 //=======================================================================
487 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor3d_Curve& theC,
488                                             const Standard_Real theAbscissa,
489                                             const Standard_Real theU0)
490 {
491   compute (theC, theAbscissa, theU0);
492 }
493
494 //=======================================================================
495 //function : GCPnts_AbscissaPoint
496 //purpose  :
497 //=======================================================================
498 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor2d_Curve2d& theC,
499                                             const Standard_Real theAbscissa,
500                                             const Standard_Real theU0)
501 {
502   compute (theC, theAbscissa, theU0);
503 }
504
505 //=======================================================================
506 //function : advCompute
507 //purpose  :
508 //=======================================================================
509 template<class TheCurve>
510 void GCPnts_AbscissaPoint::advCompute (const Standard_Real theTol,
511                                        const TheCurve& theC,
512                                        const Standard_Real theAbscissa,
513                                        const Standard_Real theU0)
514 {
515   const Standard_Real aL = GCPnts_AbscissaPoint::Length (theC, theTol);
516   /*if (aL < Precision::Confusion())
517   {
518     throw Standard_ConstructionError ("GCPnts_AbscissaPoint::GCPnts_AbscissaPoint");
519   }*/
520   Standard_Real anAbscis = theAbscissa;
521   Standard_Real aUU0 = theU0;
522   Standard_Real aUUi = 0.0;
523   if (aL >= Precision::Confusion())
524   {
525     aUUi= theU0 + (anAbscis / aL) * (theC.LastParameter() - theC.FirstParameter());
526   }
527   else
528   {
529     aUUi = theU0;
530   }
531   AdvCompute (myComputer, theC, anAbscis, aUU0, aUUi, theTol);
532 }
533
534 //=======================================================================
535 //function : GCPnts_AbscissaPoint
536 //purpose  :
537 //=======================================================================
538 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Standard_Real theTol,
539                                             const Adaptor3d_Curve& theC,
540                                             const Standard_Real theAbscissa,
541                                             const Standard_Real theU0)
542 {
543   advCompute (theTol, theC, theAbscissa, theU0);
544 }
545
546 //=======================================================================
547 //function : GCPnts_AbscissaPoint
548 //purpose  :
549 //=======================================================================
550 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Standard_Real theTol,
551                                             const Adaptor2d_Curve2d& theC,
552                                             const Standard_Real theAbscissa,
553                                             const Standard_Real theU0)
554 {
555   advCompute (theTol, theC, theAbscissa, theU0);
556 }
557
558 //=======================================================================
559 //function : GCPnts_AbscissaPoint
560 //purpose  :
561 //=======================================================================
562 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor3d_Curve& theC,
563                                             const Standard_Real theAbscissa,
564                                             const Standard_Real theU0, const Standard_Real theUi)
565 {
566   Standard_Real anAbscis = theAbscissa, aUU0 = theU0, aUUi = theUi;
567   Compute (myComputer, theC, anAbscis, aUU0, aUUi, theC.Resolution (Precision::Confusion()));
568 }
569
570 //=======================================================================
571 //function : GCPnts_AbscissaPoint
572 //purpose  :
573 //=======================================================================
574 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor2d_Curve2d& theC,
575                                             const Standard_Real theAbscissa,
576                                             const Standard_Real theU0, const Standard_Real theUi)
577 {
578   Standard_Real anAbscis = theAbscissa, aUU0 = theU0, aUUi = theUi;
579   Compute (myComputer, theC, anAbscis, aUU0, aUUi, theC.Resolution (Precision::Confusion()));
580 }
581
582 //=======================================================================
583 //function : GCPnts_AbscissaPoint
584 //purpose  :
585 //=======================================================================
586 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor3d_Curve& theC,
587                                             const Standard_Real theAbscissa,
588                                             const Standard_Real theU0, const Standard_Real theUi,
589                                             const Standard_Real theTol)
590 {
591   Standard_Real anAbscis = theAbscissa, aUU0 = theU0, aUUi = theUi;
592   AdvCompute (myComputer, theC, anAbscis, aUU0, aUUi, theTol);
593 }
594
595 //=======================================================================
596 //function : GCPnts_AbscissaPoint
597 //purpose  :
598 //=======================================================================
599 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint (const Adaptor2d_Curve2d& theC,
600                                             const Standard_Real theAbscissa,
601                                             const Standard_Real theU0, const Standard_Real theUi,
602                                             const Standard_Real theTol)
603 {
604   Standard_Real anAbscis = theAbscissa, aUU0 = theU0, aUUi = theUi;
605   AdvCompute (myComputer, theC, anAbscis, aUU0, aUUi, theTol);
606 }