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>
computeType(const TheCurve & theC,Standard_Real & theRatio)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>
Compute(CPnts_AbscissaPoint & theComputer,const TheCurve & theC,Standard_Real & theAbscis,Standard_Real & theU0,Standard_Real & theUi,const Standard_Real theEPSILON)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>
AdvCompute(CPnts_AbscissaPoint & theComputer,const TheCurve & theC,Standard_Real & theAbscis,Standard_Real & theU0,Standard_Real & theUi,const Standard_Real theEPSILON)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 //=======================================================================
GCPnts_AbscissaPoint()321 GCPnts_AbscissaPoint::GCPnts_AbscissaPoint()
322 {
323 //
324 }
325
326 //=======================================================================
327 //function : Length
328 //purpose :
329 //=======================================================================
Length(const Adaptor3d_Curve & theC)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 //=======================================================================
Length(const Adaptor2d_Curve2d & theC)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 //=======================================================================
Length(const Adaptor3d_Curve & theC,const Standard_Real theTol)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 //=======================================================================
Length(const Adaptor2d_Curve2d & theC,const Standard_Real theTol)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 //=======================================================================
Length(const Adaptor3d_Curve & theC,const Standard_Real theU1,const Standard_Real theU2)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 //=======================================================================
Length(const Adaptor2d_Curve2d & theC,const Standard_Real theU1,const Standard_Real theU2)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 //=======================================================================
Length(const Adaptor3d_Curve & theC,const Standard_Real theU1,const Standard_Real theU2,const Standard_Real theTol)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 //=======================================================================
Length(const Adaptor2d_Curve2d & theC,const Standard_Real theU1,const Standard_Real theU2,const Standard_Real theTol)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>
length(const TheCurve & theC,const Standard_Real theU1,const Standard_Real theU2,const Standard_Real * theTol)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>
compute(const TheCurve & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor3d_Curve & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor2d_Curve2d & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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>
advCompute(const Standard_Real theTol,const TheCurve & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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 //=======================================================================
GCPnts_AbscissaPoint(const Standard_Real theTol,const Adaptor3d_Curve & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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 //=======================================================================
GCPnts_AbscissaPoint(const Standard_Real theTol,const Adaptor2d_Curve2d & theC,const Standard_Real theAbscissa,const Standard_Real theU0)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor3d_Curve & theC,const Standard_Real theAbscissa,const Standard_Real theU0,const Standard_Real theUi)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor2d_Curve2d & theC,const Standard_Real theAbscissa,const Standard_Real theU0,const Standard_Real theUi)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor3d_Curve & theC,const Standard_Real theAbscissa,const Standard_Real theU0,const Standard_Real theUi,const Standard_Real theTol)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 //=======================================================================
GCPnts_AbscissaPoint(const Adaptor2d_Curve2d & theC,const Standard_Real theAbscissa,const Standard_Real theU0,const Standard_Real theUi,const Standard_Real theTol)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 }
607