0031407: [Regression to 7.3.0] Extrema does not process parallel circles correctly
[occt.git] / src / Extrema / Extrema_ExtCC.cxx
CommitLineData
b311480e 1// Created on: 1994-07-06
2// Created by: Laurent PAINNOT
3// Copyright (c) 1994-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
17// Modified by MPS (june 96) : correction du trap dans le cas droite/Bezier
18// Modified by MPS (mai 97) : PRO 7598
19// tri des solutions pour eviter de rendre plusieurs
20// fois la meme solution
21
42cf5bc1 22#include <Adaptor3d_Curve.hxx>
638ad7f3 23#include <Bnd_Range.hxx>
42cf5bc1 24#include <ElCLib.hxx>
25#include <Extrema_CurveTool.hxx>
26#include <Extrema_ECC.hxx>
27#include <Extrema_ExtCC.hxx>
7fd59977 28#include <Extrema_ExtElC.hxx>
42cf5bc1 29#include <Extrema_ExtPElC.hxx>
30#include <Extrema_POnCurv.hxx>
31#include <Extrema_SequenceOfPOnCurv.hxx>
32#include <Geom_Circle.hxx>
7fd59977 33#include <Geom_Curve.hxx>
7fd59977 34#include <Geom_Ellipse.hxx>
42cf5bc1 35#include <Geom_Hyperbola.hxx>
7fd59977 36#include <Geom_Line.hxx>
37#include <Geom_Parabola.hxx>
42cf5bc1 38#include <Geom_TrimmedCurve.hxx>
39#include <GeomAbs_CurveType.hxx>
40#include <gp_Pnt.hxx>
7fd59977 41#include <Precision.hxx>
42cf5bc1 42#include <Standard_Failure.hxx>
43#include <Standard_NotImplemented.hxx>
7fd59977 44#include <Standard_NullObject.hxx>
42cf5bc1 45#include <Standard_OutOfRange.hxx>
42cf5bc1 46#include <StdFail_NotDone.hxx>
47#include <TColStd_Array1OfReal.hxx>
48#include <TColStd_ListIteratorOfListOfTransient.hxx>
49#include <TColStd_SequenceOfReal.hxx>
0b85f9a6 50
7fd59977 51//=======================================================================
0b85f9a6 52//function : Extrema_ExtCC
7fd59977 53//purpose :
54//=======================================================================
0b85f9a6 55Extrema_ExtCC::Extrema_ExtCC (const Standard_Real TolC1,
836d7b64 56 const Standard_Real TolC2)
57: myIsFindSingleSolution(Standard_False),
58 myDone (Standard_False)
7fd59977 59{
60 myC[0] = 0; myC[1] = 0;
638ad7f3 61 myInf[0] = myInf[1] = -Precision::Infinite();
62 mySup[0] = mySup[1] = Precision::Infinite();
7fd59977 63 myTol[0] = TolC1; myTol[1] = TolC2;
638ad7f3 64 mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
7fd59977 65}
66
67//=======================================================================
0b85f9a6 68//function : Extrema_ExtCC
7fd59977 69//purpose :
70//=======================================================================
71
836d7b64 72Extrema_ExtCC::Extrema_ExtCC(const Adaptor3d_Curve& C1,
73 const Adaptor3d_Curve& C2,
74 const Standard_Real U1,
75 const Standard_Real U2,
76 const Standard_Real V1,
77 const Standard_Real V2,
78 const Standard_Real TolC1,
79 const Standard_Real TolC2)
80: myIsFindSingleSolution(Standard_False),
81 myECC(C1, C2, U1, U2, V1, V2),
4bbaf12b 82 myDone (Standard_False)
7fd59977 83{
84 SetCurve (1, C1, U1, U2);
85 SetCurve (2, C2, V1, V2);
86 SetTolerance (1, TolC1);
87 SetTolerance (2, TolC2);
638ad7f3 88 mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
7fd59977 89 Perform();
90}
91
92
93//=======================================================================
0b85f9a6 94//function : Extrema_ExtCC
7fd59977 95//purpose :
96//=======================================================================
97
0b85f9a6 98Extrema_ExtCC::Extrema_ExtCC(const Adaptor3d_Curve& C1,
836d7b64 99 const Adaptor3d_Curve& C2,
100 const Standard_Real TolC1,
101 const Standard_Real TolC2)
102: myIsFindSingleSolution(Standard_False),
103 myECC(C1, C2),
4bbaf12b 104 myDone (Standard_False)
7fd59977 105{
106 SetCurve (1, C1, C1.FirstParameter(), C1.LastParameter());
107 SetCurve (2, C2, C2.FirstParameter(), C2.LastParameter());
108 SetTolerance (1, TolC1);
109 SetTolerance (2, TolC2);
638ad7f3 110 mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
7fd59977 111 Perform();
112}
113
114//=======================================================================
115//function : SetCurve
116//purpose :
117//=======================================================================
118
0b85f9a6 119void Extrema_ExtCC::SetCurve (const Standard_Integer theRank, const Adaptor3d_Curve& C)
7fd59977 120{
0b85f9a6 121 Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetCurve()")
7fd59977 122 Standard_Integer anInd = theRank - 1;
123 myC[anInd] = (Standard_Address)&C;
7fd59977 124}
125
126//=======================================================================
127//function : SetCurve
128//purpose :
129//=======================================================================
130
0b85f9a6 131void Extrema_ExtCC::SetCurve (const Standard_Integer theRank, const Adaptor3d_Curve& C,
7fd59977 132 const Standard_Real Uinf, const Standard_Real Usup)
133{
134 SetCurve (theRank, C);
135 SetRange (theRank, Uinf, Usup);
136}
137
138//=======================================================================
139//function : SetRange
140//purpose :
141//=======================================================================
142
0b85f9a6 143void Extrema_ExtCC::SetRange (const Standard_Integer theRank,
7fd59977 144 const Standard_Real Uinf, const Standard_Real Usup)
145{
0b85f9a6 146 Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetRange()")
7fd59977 147 Standard_Integer anInd = theRank - 1;
148 myInf[anInd] = Uinf;
149 mySup[anInd] = Usup;
150}
151
152//=======================================================================
153//function : SetTolerance
154//purpose :
155//=======================================================================
156
0b85f9a6 157void Extrema_ExtCC::SetTolerance (const Standard_Integer theRank, const Standard_Real theTol)
7fd59977 158{
0b85f9a6 159 Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetTolerance()")
7fd59977 160 Standard_Integer anInd = theRank - 1;
161 myTol[anInd] = theTol;
162}
163
164
165//=======================================================================
166//function : Perform
167//purpose :
168//=======================================================================
169
0b85f9a6 170void Extrema_ExtCC::Perform()
7fd59977 171{
0b85f9a6 172 Standard_NullObject_Raise_if (!myC[0] || !myC[1], "Extrema_ExtCC::Perform()")
4bbaf12b 173 myECC.SetParams(*((Adaptor3d_Curve*)myC[0]),
174 *((Adaptor3d_Curve*)myC[1]), myInf[0], mySup[0], myInf[1], mySup[1]);
5493d334 175 myECC.SetTolerance(Min(myTol[0], myTol[1]));
836d7b64 176 myECC.SetSingleSolutionFlag(GetSingleSolutionFlag());
7fd59977 177 myDone = Standard_False;
178 mypoints.Clear();
179 mySqDist.Clear();
180 myIsPar = Standard_False;
181
0b85f9a6 182 GeomAbs_CurveType type1 = (*((Adaptor3d_Curve*)myC[0])).GetType();
183 GeomAbs_CurveType type2 = (*((Adaptor3d_Curve*)myC[1])).GetType();
7fd59977 184 Standard_Real U11, U12, U21, U22, Tol = Min(myTol[0], myTol[1]);
7fd59977 185
186 U11 = myInf[0];
187 U12 = mySup[0];
188 U21 = myInf[1];
189 U22 = mySup[1];
190
0b85f9a6 191 if (!Precision::IsInfinite(U11)) P1f = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[0]), U11);
192 if (!Precision::IsInfinite(U12)) P1l = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[0]), U12);
193 if (!Precision::IsInfinite(U21)) P2f = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[1]), U21);
194 if (!Precision::IsInfinite(U22)) P2l = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[1]), U22);
7fd59977 195
196
197 if (Precision::IsInfinite(U11) || Precision::IsInfinite(U21)) mydist11 = RealLast();
198 else mydist11 = P1f.SquareDistance(P2f);
199 if (Precision::IsInfinite(U11) || Precision::IsInfinite(U22)) mydist12 = RealLast();
200 else mydist12 = P1f.SquareDistance(P2l);
201 if (Precision::IsInfinite(U12) || Precision::IsInfinite(U21)) mydist21 = RealLast();
202 else mydist21 = P1l.SquareDistance(P2f);
203 if (Precision::IsInfinite(U12) || Precision::IsInfinite(U22)) mydist22 = RealLast();
204 else mydist22 = P1l.SquareDistance(P2l);
205
7fd59977 206 //Depending on the types of curves, the algorithm is chosen:
207 //- _ExtElC, when one of the curves is a line and the other is elementary,
208 // or there are two circles;
209 //- _GenExtCC, in all other cases
210 if ( (type1 == GeomAbs_Line && type2 <= GeomAbs_Parabola) ||
211 (type2 == GeomAbs_Line && type1 <= GeomAbs_Parabola) ) {
212 //analytical case - one curve is always a line
213 Standard_Integer anInd1 = 0, anInd2 = 1;
214 GeomAbs_CurveType aType2 = type2;
638ad7f3 215 Standard_Boolean isInverse = (type1 > type2);
216 if (isInverse)
217 {
7fd59977 218 //algorithm uses inverse order of arguments
219 anInd1 = 1;
220 anInd2 = 0;
221 aType2 = type1;
222 }
223 switch (aType2) {
224 case GeomAbs_Line: {
0b85f9a6 225 Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Line(), Tol);
638ad7f3 226 PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
7fd59977 227 break;
228 }
229 case GeomAbs_Circle: {
0b85f9a6 230 Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Circle(), Tol);
638ad7f3 231 PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
7fd59977 232 break;
233 }
234 case GeomAbs_Ellipse: {
0b85f9a6 235 Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Ellipse());
638ad7f3 236 PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
7fd59977 237 break;
238 }
239 case GeomAbs_Hyperbola: {
0b85f9a6 240 Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Hyperbola());
638ad7f3 241 PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
7fd59977 242 break;
243 }
244 case GeomAbs_Parabola: {
0b85f9a6 245 Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Parabola());
638ad7f3 246 PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
7fd59977 247 break;
248 }
249 default: break;
250 }
251 } else if (type1 == GeomAbs_Circle && type2 == GeomAbs_Circle) {
252 //analytical case - two circles
253 Standard_Boolean bIsDone;
0b85f9a6 254 Extrema_ExtElC CCXtrem ((*((Adaptor3d_Curve*)myC[0])).Circle(), (*((Adaptor3d_Curve*)myC[1])).Circle());
7fd59977 255 bIsDone = CCXtrem.IsDone();
7fd59977 256 if(bIsDone) {
638ad7f3 257 PrepareResults(CCXtrem, Standard_False, U11, U12, U21, U22);
7fd59977 258 }
7fd59977 259 else {
7fd59977 260 myECC.Perform();
638ad7f3 261 PrepareResults(myECC, U11, U12, U21, U22);
7fd59977 262 }
263 } else {
4bbaf12b 264 myECC.Perform();
638ad7f3 265 PrepareResults(myECC, U11, U12, U21, U22);
7fd59977 266 }
267}
268
269
270//=======================================================================
271//function : IsDone
272//purpose :
273//=======================================================================
274
0b85f9a6 275Standard_Boolean Extrema_ExtCC::IsDone() const
7fd59977 276{
277 return myDone;
278}
279
280//=======================================================================
281//function : IsParallel
282//purpose :
283//=======================================================================
284
0b85f9a6 285Standard_Boolean Extrema_ExtCC::IsParallel() const
7fd59977 286{
638ad7f3 287 if (!IsDone())
288 {
289 throw StdFail_NotDone();
290 }
291
7fd59977 292 return myIsPar;
293}
294
295
296//=======================================================================
297//function : Value
298//purpose :
299//=======================================================================
300
0b85f9a6 301Standard_Real Extrema_ExtCC::SquareDistance(const Standard_Integer N) const
7fd59977 302{
638ad7f3 303 if ((N < 1) || (N > NbExt())) throw Standard_OutOfRange();
7fd59977 304 return mySqDist.Value(N);
305}
306
307
308//=======================================================================
309//function : NbExt
310//purpose :
311//=======================================================================
312
0b85f9a6 313Standard_Integer Extrema_ExtCC::NbExt() const
7fd59977 314{
9775fa61 315 if(!myDone) throw StdFail_NotDone();
638ad7f3 316 return mySqDist.Length();
7fd59977 317}
318
319
320//=======================================================================
321//function : Points
322//purpose :
323//=======================================================================
324
0b85f9a6 325void Extrema_ExtCC::Points(const Standard_Integer N,
7fd59977 326 Extrema_POnCurv& P1,
327 Extrema_POnCurv& P2) const
328{
638ad7f3 329 if (N < 1 || N > NbExt())
330 {
331 throw Standard_OutOfRange();
332 }
333
334 P1 = mypoints.Value(2 * N - 1);
335 P2 = mypoints.Value(2 * N);
7fd59977 336}
337
338
339
340//=======================================================================
341//function : TrimmedDistances
342//purpose :
343//=======================================================================
344
0b85f9a6 345void Extrema_ExtCC::TrimmedSquareDistances(Standard_Real& dist11,
7fd59977 346 Standard_Real& dist12,
347 Standard_Real& dist21,
348 Standard_Real& dist22,
349 gp_Pnt& P11 ,
350 gp_Pnt& P12 ,
351 gp_Pnt& P21 ,
352 gp_Pnt& P22 ) const {
353
354 dist11 = mydist11;
355 dist12 = mydist12;
356 dist21 = mydist21;
357 dist22 = mydist22;
358 P11 = P1f;
359 P12 = P1l;
360 P21 = P2f;
361 P22 = P2l;
362}
363
638ad7f3 364//=======================================================================
365//function : ParallelResult
366//purpose :
367//=======================================================================
368void Extrema_ExtCC::PrepareParallelResult(const Standard_Real theUt11,
369 const Standard_Real theUt12,
370 const Standard_Real theUt21,
371 const Standard_Real theUt22,
372 const Standard_Real theSqDist)
373{
374 if (!myIsPar)
375 return;
7fd59977 376
638ad7f3 377 const GeomAbs_CurveType aType1 = Extrema_CurveTool::GetType(*((Adaptor3d_Curve*) myC[0]));
378 const GeomAbs_CurveType aType2 = Extrema_CurveTool::GetType(*((Adaptor3d_Curve*) myC[1]));
379
380 if (((aType1 != GeomAbs_Line) && (aType1 != GeomAbs_Circle)) ||
381 ((aType2 != GeomAbs_Line) && (aType2 != GeomAbs_Circle)))
382 {
383 mySqDist.Append(theSqDist);
384 myDone = Standard_True;
385 myIsPar = Standard_True;
386 return;
387 }
388
389 // Parallel case is only for line-line, circle-circle and circle-line!!!
390 // But really for trimmed curves extremas can not exist!
391 if (aType1 != aType2)
392 {
393 //The projection of the circle's location to the trimmed line must exist.
394 const Standard_Boolean isReversed = (aType1 != GeomAbs_Circle);
395 const gp_Pnt aPonC = !isReversed ?
396 Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[0]), theUt11) :
397 Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[1]), theUt21);
398
399 const gp_Lin aL = !isReversed ? ((Adaptor3d_Curve*) myC[1])->Line() :
400 ((Adaptor3d_Curve*) myC[0])->Line();
401 const Extrema_ExtPElC ExtPLin(aPonC, aL, Precision::Confusion(),
402 !isReversed ? theUt21 : theUt11,
403 !isReversed ? theUt22 : theUt12);
404
405 if (ExtPLin.IsDone())
406 {
407 mySqDist.Append(theSqDist);
408 }
409 else
410 {
411 myIsPar = Standard_False;
412 }
413
414 return;
415 }
416
417 if (aType1 == GeomAbs_Line)
418 {
419 // Line - Line
420
421 const Standard_Real isFirstInfinite = (Precision::IsInfinite(theUt11) &&
422 Precision::IsInfinite(theUt12));
423 const Standard_Real isLastInfinite = (Precision::IsInfinite(theUt21) &&
424 Precision::IsInfinite(theUt22));
425
426 if (isFirstInfinite || isLastInfinite)
427 {
428 // Infinite number of solution
429
430 mySqDist.Append(theSqDist);
431 }
432 else
433 {
434 // The range created by projection of both ends of the 1st line
435 // to the 2nd one must intersect the (native) trimmed range of
436 // the 2nd line.
437
438 myIsPar = Standard_False;
439
440 const gp_Lin aLin1 = ((Adaptor3d_Curve*) myC[0])->Line();
441 const gp_Lin aLin2 = ((Adaptor3d_Curve*) myC[1])->Line();
442 const Standard_Boolean isOpposite(aLin1.Direction().Dot(aLin2.Direction()) < 0.0);
443
444 Bnd_Range aRange2(theUt21, theUt22);
445 Bnd_Range aProjRng12;
446
447 if (Precision::IsInfinite(theUt11))
448 {
449 if (isOpposite)
450 aProjRng12.Add(Precision::Infinite());
451 else
452 aProjRng12.Add(-Precision::Infinite());
453 }
454 else
455 {
456 const gp_Pnt aPonC1 = ElCLib::Value(theUt11, aLin1);
457 const Standard_Real aPar = ElCLib::Parameter(aLin2, aPonC1);
458 aProjRng12.Add(aPar);
459 }
460
461 if (Precision::IsInfinite(theUt12))
462 {
463 if (isOpposite)
464 aProjRng12.Add(-Precision::Infinite());
465 else
466 aProjRng12.Add(Precision::Infinite());
467 }
468 else
469 {
470 const gp_Pnt aPonC1 = ElCLib::Value(theUt12, aLin1);
471 const Standard_Real aPar = ElCLib::Parameter(aLin2, aPonC1);
472 aProjRng12.Add(aPar);
473 }
474
475 aRange2.Common(aProjRng12);
476 if (aRange2.Delta() > Precision::Confusion())
477 {
478 ClearSolutions();
479 mySqDist.Append(theSqDist);
480 myIsPar = Standard_True;
481 }
482 else if (!aRange2.IsVoid())
483 {
484 //Case like this:
485
486 // ************** aLin1
487 // o
488 // o
489 // *************** aLin2
490
491 ClearSolutions();
492 Standard_Real aPar1 = 0.0, aPar2 = 0.0;
493 aRange2.GetBounds(aPar1, aPar2);
494 aPar2 = 0.5*(aPar1 + aPar2);
495 gp_Pnt aP = ElCLib::Value(aPar2, aLin2);
496 const Extrema_POnCurv aP2(aPar2, aP);
497 aPar1 = ElCLib::Parameter(aLin1, aP);
498 aP = ElCLib::Value(aPar1, aLin1);
499 const Extrema_POnCurv aP1(aPar1, aP);
500 mypoints.Append(aP1);
501 mypoints.Append(aP2);
502 mySqDist.Append(theSqDist);
503 }
504 }
505 }
506 else
507 {
508 // Circle - Circle
509 myIsPar = Standard_False;
510
511 //Two arcs with ranges [U1, U2] and [V1, V2] correspondingly are
512 //considered to be parallel in the following case:
513 // The range created by projection both points U1 and U2 of the
514 // 1st circle to the 2nd one intersects either the range [V1, V2] or
515 // the range [V1-PI, V2-PI]. All ranges must be adjusted to correspond
516 // periodic range before checking of intersection.
517
518 const gp_Circ aWorkCirc = ((Adaptor3d_Curve*) myC[1])->Circle();
519 const Standard_Real aPeriod = M_PI + M_PI;
520 gp_Vec aVTg1;
521 gp_Pnt aP11;
522 const gp_Pnt aP12 = Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[0]), theUt12);
523 Extrema_CurveTool::D1(*((Adaptor3d_Curve*) myC[0]), theUt11, aP11, aVTg1);
524
525 const Bnd_Range aRange(theUt21, theUt22);
526 Bnd_Range aProjRng1;
527
528 // Project arc of the 1st circle between points theUt11 and theUt12 to the
529 // 2nd circle. It is necessary to chose correct arc from two possible ones.
530
531 Standard_Real aPar1 = ElCLib::InPeriod(ElCLib::Parameter(aWorkCirc, aP11),
532 theUt21, theUt21 + aPeriod);
533 const gp_Vec aVTg2 = Extrema_CurveTool::DN(*((Adaptor3d_Curve*) myC[1]), aPar1, 1);
534
535 // Check if circles have same/opposite directions
536 const Standard_Boolean isOpposite(aVTg1.Dot(aVTg2) < 0.0);
537
538 Standard_Real aPar2 = ElCLib::InPeriod(ElCLib::Parameter(aWorkCirc, aP12),
539 theUt21, theUt21 + aPeriod);
540
541 if (isOpposite)
542 {
543 // Must be aPar2 < aPar1
544 if ((aRange.Delta() > Precision::Angular()) &&
545 ((aPar1 - aPar2) < Precision::Angular()))
546 {
547 aPar2 -= aPeriod;
548 }
549 }
550 else
551 {
552 // Must be aPar2 > aPar1
553 if ((aRange.Delta() > Precision::Angular()) &&
554 ((aPar2 - aPar1) < Precision::Angular()))
555 {
d6e18114 556 aPar2 += aPeriod;
638ad7f3 557 }
558 }
559
560 // Now the projection result is the range [aPar1, aPar2]
561 // if aPar1 < aPar2 or the range [aPar2, aPar1], otherwise.
562
563 Standard_Real aMinSquareDist = RealLast();
564
d6e18114 565 aProjRng1.Add(aPar1 - aPeriod);
566 aProjRng1.Add(aPar2 - aPeriod);
567 for (Standard_Integer i = 0; i < 3; i++)
638ad7f3 568 {
d6e18114 569 // Repeat computation three times, shifting the range to PI on each step,
570 // to be able to find if the concentric arcs ranges are intersected in just one parameter
571 // (lower or upper boundary).
638ad7f3 572
573 Bnd_Range aRng = aProjRng1;
574 aRng.Common(aRange);
575
576 //Cases are possible and processed below:
577 //1. Extrema does not exist. In this case all common ranges are VOID.
578 //2. Arcs are parallel and distance between them is equal to sqrt(theSqDist).
579 // In this case myIsPar = TRUE definitely.
580 //3. Arcs are parallel and distance between them is equal to (sqrt(theSqDist) + R),
581 // where R is the least radius of the both circles. In this case myIsPar flag
582 // will temporary be set to TRUE but check will be continued until less
583 // distance will be found. At that, region with the least distance can be
584 // either a local point or continuous range. In 1st case myIsPar = FALSE and
585 // several (or single) extremas will be returned. In the 2nd one
586 // myIsPar = TRUE and only the least distance will be returned.
587 //4. Arcs are not parallel. Then several (or single) extremas will be returned.
588
589 if (aRng.Delta() > Precision::Angular())
590 {
591 Standard_Real aPar = 0.0;
592 aRng.GetIntermediatePoint(0.5, aPar);
593 const gp_Pnt aPCirc2 = ElCLib::Value(aPar, aWorkCirc);
594 Extrema_ExtPElC ExtPCir(aPCirc2,
595 Extrema_CurveTool::Circle(*((Adaptor3d_Curve*) myC[0])),
596 Precision::Confusion(), theUt11, theUt12);
597
598 Standard_Real aMinSqD = ExtPCir.SquareDistance(1);
599 for (Standard_Integer anExtID = 2; anExtID <= ExtPCir.NbExt(); anExtID++)
600 {
601 aMinSqD = Min(aMinSqD, ExtPCir.SquareDistance(anExtID));
602 }
603
604 if (aMinSqD <= aMinSquareDist)
605 {
606 ClearSolutions();
607 mySqDist.Append(aMinSqD);
608 myIsPar = Standard_True;
609
610 const Standard_Real aDeltaSqDist = aMinSqD - theSqDist;
611 const Standard_Real aSqD = Max(aMinSqD, theSqDist);
612
613 // 0 <= Dist1-Dist2 <= Eps
614 // 0 <= Dist1^2 - Dist2^2 < Eps*(Dist1+Dist2)
615
616 //If Dist1 ~= Dist2 ==> Dist1+Dist2 ~= 2*Dist2.
617 //Consequently,
618 // 0 <= Dist1^2 - Dist2^2 <= 2*Dist2*Eps
619
620 //Or
621 // (Dist1^2 - Dist2^2)^2 <= 4*Dist2^2*Eps^2
622
623 if (aDeltaSqDist*aDeltaSqDist < 4.0*aSqD*Precision::SquareConfusion())
624 {
625 // New solution is found
626 break;
627 }
628 }
629
630 //Nearer solution can be found
631 }
632 else if (!aRng.IsVoid())
633 {
634 //Check cases like this:
635
636 // ************** aCirc1
637 // o
638 // o
639 // *************** aCirc2
640
641 Standard_Real aPar = 0.0;
642 aRng.GetIntermediatePoint(0.5, aPar);
643 const gp_Pnt aPCirc2 = ElCLib::Value(aPar, aWorkCirc);
644 const Extrema_POnCurv aP2(aPar, aPCirc2);
645
646 Extrema_ExtPElC ExtPCir(aPCirc2,
647 Extrema_CurveTool::Circle(*((Adaptor3d_Curve*) myC[0])),
648 Precision::Confusion(), theUt11, theUt12);
649
650 Standard_Boolean isFound = !myIsPar;
651
652 if (!isFound)
653 {
654 //If the flag myIsPar was set earlier then it does not mean that
655 //we have found the minimal distance. Here we check it. If there is
656 //a pair of points, which are in less distance then myIsPar flag
657 //was unset and the algorithm will return these nearest points.
658
659 for (Standard_Integer anExtID = 1; anExtID <= ExtPCir.NbExt(); anExtID++)
660 {
661 if (ExtPCir.SquareDistance(anExtID) < aMinSquareDist)
662 {
663 isFound = Standard_True;
664 break;
665 }
666 }
667 }
668
669 if (isFound)
670 {
671 ClearSolutions();
672 myIsPar = Standard_False;
673 for (Standard_Integer anExtID = 1; anExtID <= ExtPCir.NbExt(); anExtID++)
674 {
675 mypoints.Append(ExtPCir.Point(anExtID));
676 mypoints.Append(aP2);
677 mySqDist.Append(ExtPCir.SquareDistance(anExtID));
678 aMinSquareDist = Min(aMinSquareDist, ExtPCir.SquareDistance(anExtID));
679 }
680 }
681 }
682
683 aProjRng1.Shift(M_PI);
684 }
685 }
686}
7fd59977 687
688//=======================================================================
689//function : Results
690//purpose :
691//=======================================================================
692
638ad7f3 693void Extrema_ExtCC::PrepareResults(const Extrema_ExtElC& AlgExt,
694 const Standard_Boolean theIsInverse,
695 const Standard_Real Ut11,
696 const Standard_Real Ut12,
697 const Standard_Real Ut21,
698 const Standard_Real Ut22)
7fd59977 699{
700 Standard_Integer i, NbExt;
701 Standard_Real Val, U, U2;
702 Extrema_POnCurv P1, P2;
703
704 myDone = AlgExt.IsDone();
705 if (myDone) {
706 myIsPar = AlgExt.IsParallel();
707 if (myIsPar) {
638ad7f3 708 PrepareParallelResult(Ut11, Ut12, Ut21, Ut22, AlgExt.SquareDistance());
7fd59977 709 }
710 else {
711 NbExt = AlgExt.NbExt();
712 for (i = 1; i <= NbExt; i++) {
713 // Verification de la validite des parametres
714 AlgExt.Points(i, P1, P2);
638ad7f3 715 if (!theIsInverse)
716 {
7fd59977 717 U = P1.Parameter();
718 U2 = P2.Parameter();
719 }
720 else {
721 U2 = P1.Parameter();
722 U = P2.Parameter();
723 }
724
0b85f9a6 725 if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*)myC[0]))) {
726 U = ElCLib::InPeriod(U, Ut11, Ut11+Extrema_CurveTool::Period(*((Adaptor3d_Curve*)myC[0])));
7fd59977 727 }
0b85f9a6 728 if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*)myC[1]))) {
729 U2 = ElCLib::InPeriod(U2, Ut21, Ut21+Extrema_CurveTool::Period(*((Adaptor3d_Curve*)myC[1])));
7fd59977 730 }
731
732 if ((U >= Ut11 - RealEpsilon()) &&
733 (U <= Ut12 + RealEpsilon()) &&
734 (U2 >= Ut21 - RealEpsilon()) &&
735 (U2 <= Ut22 + RealEpsilon())) {
7fd59977 736 Val = AlgExt.SquareDistance(i);
737 mySqDist.Append(Val);
638ad7f3 738 if (!theIsInverse)
739 {
7fd59977 740 P1.SetValues(U, P1.Value());
741 P2.SetValues(U2, P2.Value());
742 mypoints.Append(P1);
743 mypoints.Append(P2);
744 }
745 else {
746 P1.SetValues(U2, P1.Value());
747 P2.SetValues(U, P2.Value());
748 mypoints.Append(P2);
749 mypoints.Append(P1);
750 }
751 }
752 }
753 }
754 }
755
756}
757
758
759//=======================================================================
760//function : Results
761//purpose :
762//=======================================================================
763
638ad7f3 764void Extrema_ExtCC::PrepareResults(const Extrema_ECC& AlgExt,
765 const Standard_Real Ut11,
766 const Standard_Real Ut12,
767 const Standard_Real Ut21,
768 const Standard_Real Ut22)
7fd59977 769{
20a216fe 770 Standard_Integer i, NbExt;
771 Standard_Real Val, U, U2;
772 Extrema_POnCurv P1, P2;
7fd59977 773
774 myDone = AlgExt.IsDone();
20a216fe 775 if (myDone)
776 {
777 myIsPar = AlgExt.IsParallel();
638ad7f3 778 if (myIsPar)
20a216fe 779 {
638ad7f3 780 PrepareParallelResult(Ut11, Ut12, Ut21, Ut22, AlgExt.SquareDistance());
781 }
782 else
783 {
784 NbExt = AlgExt.NbExt();
785 for (i = 1; i <= NbExt; i++)
20a216fe 786 {
638ad7f3 787 AlgExt.Points(i, P1, P2);
788 U = P1.Parameter();
789 U2 = P2.Parameter();
790
791 // Check points to be into param space.
792 if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*) myC[0])))
793 {
794 U = ElCLib::InPeriod(U, Ut11, Ut11 + Extrema_CurveTool::Period(*((Adaptor3d_Curve*) myC[0])));
795 }
796 if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*) myC[1])))
797 {
798 U2 = ElCLib::InPeriod(U2, Ut21, Ut21 + Extrema_CurveTool::Period(*((Adaptor3d_Curve*) myC[1])));
799 }
800
801 if ((U >= Ut11 - RealEpsilon()) &&
802 (U <= Ut12 + RealEpsilon()) &&
803 (U2 >= Ut21 - RealEpsilon()) &&
804 (U2 <= Ut22 + RealEpsilon()))
805 {
806 Val = AlgExt.SquareDistance(i);
807 mySqDist.Append(Val);
808 P1.SetValues(U, P1.Value());
809 P2.SetValues(U2, P2.Value());
810 mypoints.Append(P1);
811 mypoints.Append(P2);
812 }
7fd59977 813 }
814 }
20a216fe 815 }
7fd59977 816}
836d7b64 817
818//=======================================================================
819//function : SetSingleSolutionFlag
820//purpose :
821//=======================================================================
822void Extrema_ExtCC::SetSingleSolutionFlag(const Standard_Boolean theFlag)
823{
824 myIsFindSingleSolution = theFlag;
825}
826
827//=======================================================================
828//function : GetSingleSolutionFlag
829//purpose :
830//=======================================================================
831Standard_Boolean Extrema_ExtCC::GetSingleSolutionFlag() const
832{
833 return myIsFindSingleSolution;
834}