0023142: GccAna : suspicious else
[occt.git] / src / GccAna / GccAna_Circ2d2TanRad.cxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 //
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
8 //
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 //
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
18
19
20
21
22 #include <GccAna_Circ2d2TanRad.ixx>
23
24 #include <ElCLib.hxx>
25 #include <gp_Ax2d.hxx>
26 #include <gp_Circ2d.hxx>
27 #include <gp_Lin2d.hxx>
28 #include <IntAna2d_AnaIntersection.hxx>
29 #include <IntAna2d_IntPoint.hxx>
30 #include <Standard_NegativeValue.hxx>
31 #include <Standard_OutOfRange.hxx>
32 #include <StdFail_NotDone.hxx>
33 #include <GccEnt_BadQualifier.hxx>
34 #include <Precision.hxx>
35
36 // circular tangent to two cercles and given radius
37 //====================================================
38 //==================================================================
39 // Initialize WellDone to false.                                   +
40 // Return circle C1 and circle C2.                                 +
41 // Leave with error if the construction is impossible.             +
42 // Distinguish boundary cases to process them separately.          +
43 // Create parallel to C1 in the proper direction.                  +
44 // Create parallel to C2 in the proper direction.                  +
45 // Intersect parallels ==> center point of the solution.           +
46 // Create the solution to be added to already found solutions.     +
47 // Fill the fields.                                                +
48 //==================================================================
49
50 GccAna_Circ2d2TanRad::
51    GccAna_Circ2d2TanRad (const GccEnt_QualifiedCirc& Qualified1 ,
52                          const GccEnt_QualifiedCirc& Qualified2 ,
53                          const Standard_Real         Radius     ,
54                          const Standard_Real         Tolerance  ):
55    qualifier1(1,8) ,
56    qualifier2(1,8),
57    TheSame1(1,8)   ,
58    TheSame2(1,8)   ,
59    cirsol(1,8)     ,
60    pnttg1sol(1,8)  ,
61    pnttg2sol(1,8)  ,
62    par1sol(1,8)    ,
63    par2sol(1,8)    ,
64    pararg1(1,8)    ,
65    pararg2(1,8)    
66 {
67
68    Standard_Real Tol = Abs(Tolerance);
69    gp_Dir2d dirx(1.,0.);
70    WellDone = Standard_False;
71    NbrSol = 0;
72    if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
73          Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
74        !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
75          Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
76      GccEnt_BadQualifier::Raise();
77      return;
78    }
79    Standard_Boolean invers = Standard_False;
80    gp_Circ2d C1 = Qualified1.Qualified();
81    gp_Circ2d C2 = Qualified2.Qualified();
82    Standard_Real R1 = C1.Radius();
83    Standard_Real R2 = C2.Radius();
84    Standard_Real rbid = 0.;
85    Standard_Integer signe=0;
86    Standard_Real R3;
87    Standard_Real dist;
88    TColgp_Array1OfCirc2d C(1,8);
89    C(1) = gp_Circ2d(C1);
90    C(2) = gp_Circ2d(C2);
91    Standard_Integer nbsol = 0;
92    gp_Pnt2d center1(C1.Location());
93    gp_Pnt2d center2(C2.Location());
94    gp_Pnt2d center3;
95    if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
96    else if ( C(2).Location().IsEqual(C(1).Location(),Precision::Confusion())){
97      WellDone = Standard_True;
98    }
99    else {
100      gp_Dir2d dir1(C(2).Location().XY()-C(1).Location().XY());
101      dist = (center2).Distance(center1);
102      if ((Qualified1.IsEnclosed()) && Qualified2.IsEnclosed()) {
103 //   =========================================================
104        if (Radius*2.0-Abs(R1+R2-dist) > Tol) { WellDone = Standard_True; }
105        else {
106          if ((dist-R1-R2>Tol)||(Tol<Max(R1,R2)-dist-Min(R1,R2))) {
107            WellDone = Standard_True;
108          }
109          else if (Abs(dist-R1-R2)<=Tol||Abs(Max(R1,R2)-dist-Min(R1,R2))<=Tol) {
110            if (Abs(dist-R1-R2) <= Tol) {
111              rbid = R2+(dist-R1-R2)/2.0;
112              signe = -1;
113            }
114            else if (Abs(Max(R1,R2)-dist-Min(R1,R2)) <= Tol) {
115              if (R1 > R2) { R3 = R2; }
116              else {
117                C2 = gp_Circ2d(C1);
118                R3 = R1;
119              }
120              rbid = -R3+(Min(R1,R2)+dist-Max(R1,R2))/2.;
121              signe = 1;
122            }
123            gp_Ax2d axe(gp_Pnt2d(center2.XY()-rbid*dir1.XY()),dirx);
124            cirsol(1) = gp_Circ2d(axe,Radius);
125 //         =================================
126            qualifier1(1) = Qualified1.Qualifier();
127            qualifier2(1) = Qualified2.Qualifier();
128            pnttg1sol(1)=gp_Pnt2d(center2.XY()+signe*R2*dir1.XY());
129            pnttg2sol(1)=gp_Pnt2d(center1.XY()+R1*dir1.XY());
130            TheSame1(1)  = 0;
131            TheSame2(1)  = 0;
132            WellDone = Standard_True;
133            NbrSol = 1;
134          }
135          else {
136            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
137            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Abs(Radius-R2));
138            nbsol = 1;
139          }
140        }
141      }
142      else if (((Qualified1.IsEnclosed()) && Qualified2.IsEnclosing()) ||
143 //   ===================================================================
144               ((Qualified1.IsEnclosing()) && Qualified2.IsEnclosed())) {
145 //            ========================================================
146        if (Qualified1.IsEnclosing()) {
147          R3 = R1;
148          C(1) = gp_Circ2d(C2);
149          R1 = R2;
150          C(2) = gp_Circ2d(C1);
151          R2 = R3;
152          center3 = center1;
153          center1 = center2;
154          center2 = center3;
155          dir1.Reverse();
156          // it is necessary to swap the resulting tangency points
157          invers = Standard_True;
158        }
159        if ((R2-Radius>Tol) || (Tol<Radius-R1) || (Tol>R1-dist-R2) ||
160            ((Tol<Radius*2-R1-dist-R2)||(Tol<R1+R2-dist-Radius*2.0))) {
161          WellDone = Standard_True;
162        }
163        else if ((Abs(R2-Radius)<=Tol) || (Abs(R1-Radius)<=Tol)) {
164          if (Abs(R2-Radius) <= Tol) {
165            C(2) = gp_Circ2d(C2);
166            R3 = R2;
167            TheSame2(1) = 1;
168            TheSame1(1) = 0;
169            pnttg1sol(1) = gp_Pnt2d(C(2).Location().XY()+R3*dir1.XY());
170          }
171          else if (Abs(Radius-R1) <= Tol) {
172            C(2) = gp_Circ2d(C1);
173            R3 = R1;
174            TheSame1(1) = 1;
175            TheSame2(1) = 0;
176            pnttg2sol(1) = gp_Pnt2d(C(2).Location().XY()+R3*dir1.XY());
177          }
178          WellDone = Standard_True;
179          NbrSol = 1;
180          gp_Ax2d axe(C(2).Location(),dirx);
181          cirsol(1) = gp_Circ2d(axe,Radius);
182 //       =================================
183          qualifier1(1) = Qualified1.Qualifier();
184          qualifier2(1) = Qualified2.Qualifier();
185        }
186        else {
187          if ((Abs(R2+dist-R1) <= Tol) || (Abs(Radius*2.0-R1-dist-R2) < Tol)) {
188            if (Abs(R2+dist-R1) <= Tol) { signe = 1; }
189            else if (Abs(Radius*2.0-R1-dist-R2) < Tol) {signe = -1; }
190            WellDone = Standard_True;
191            NbrSol = 1;
192            gp_Ax2d axe(gp_Pnt2d(center1.XY()+
193                                 signe*(R1-Radius)*dir1.XY()),dirx);
194            cirsol(1) = gp_Circ2d(axe,Radius);
195 //         =================================
196            qualifier1(1) = Qualified1.Qualifier();
197            qualifier2(1) = Qualified2.Qualifier();
198            pnttg1sol(1) = gp_Pnt2d(center1.XY()+signe*R1*dir1.XY());
199            pnttg2sol(1)=gp_Pnt2d(center2.XY()+R2*dir1.XY());
200            TheSame1(1)  = 0;
201            TheSame2(1)  = 0;
202          }
203          else {
204            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
205            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Abs(Radius-R2));
206            nbsol = 1;
207          }
208        }
209      }
210      else if (((Qualified1.IsEnclosed()) && (Qualified2.IsOutside())) ||
211 //   ===================================================================
212               ((Qualified1.IsOutside()) && (Qualified2.IsEnclosed()))) {
213 //            ========================================================
214        if (Qualified1.IsOutside()) {
215          C(2) = gp_Circ2d(C1);
216          C(1) = gp_Circ2d(C2);
217          R3 = R1;
218          R1 = R2;
219          R2 = R3;
220          center3 = center1;
221          center1 = center2;
222          center2 = center3;
223          dir1.Reverse();
224          // it is necessary to swap the resulting tangency points
225          invers = Standard_True;
226        }
227        if ((Radius-R1>Tol)||(dist-R2-R1>Tol)||
228            ((R2-dist-R1+Radius*2>Tol)||(R1-R2-dist-Radius*2>Tol))){
229          WellDone = Standard_True;
230        }
231        else {
232          if (((Radius-R1 > 0.0) && (Abs(dist-R1-R2) <= Tol)) ||
233              (Abs(R1-R2+dist-Radius*2.0) <= Tol) ||
234              (Abs(R1-R2-dist-Radius*2.0) <= Tol) || (Abs(dist-R1-R2) <= Tol)) {
235            if (Abs(R1-R2+dist-Radius*2.0) <= Tol) {
236              signe = -1;
237            }
238            else {
239              signe = 1;
240              if ((Radius-R1 > 0.0) && (Abs(dist-R1-R2) <= Tol)) {
241                R2 = R1;
242              }
243              else if (Abs(dist-R1-R2) <= Tol) {
244                R2 = R1;
245                if (Abs(R1-Radius) <= Tol) {
246                  TheSame1(1) = 1;
247                }
248              }
249            }
250            WellDone = Standard_True;
251            NbrSol = 1;
252            gp_Ax2d axe(gp_Pnt2d(center1.XY()+
253                                 signe*(R1-Radius)*dir1.XY()),dirx);
254            cirsol(1) = gp_Circ2d(axe,Radius);
255 //         =================================
256            qualifier1(1) = Qualified1.Qualifier();
257            qualifier2(1) = Qualified2.Qualifier();
258            pnttg1sol(1) = gp_Pnt2d(center1.XY()+signe*R1*dir1.XY());
259            pnttg2sol(1) = gp_Pnt2d(center2.XY()+signe*R2*dir1.XY());
260            TheSame1(1)  = 0;
261            TheSame2(1)  = 0;
262          }
263          else {
264            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
265            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
266            nbsol = 1;
267          }
268        }
269      }
270      else if (((Qualified1.IsEnclosed()) && (Qualified2.IsUnqualified())) ||
271 //   =======================================================================
272               ((Qualified1.IsUnqualified()) && (Qualified2.IsEnclosed()))) {
273 //            ============================================================
274        if (Qualified1.IsUnqualified()) {
275          C(1) = gp_Circ2d(C2);
276          C(2) = gp_Circ2d(C1);
277          R3 = R1;
278          R1 = R2;
279          R2 = R3;
280          center3 = center1;
281          center1 = center2;
282          center2 = center3;
283          dir1.Reverse();
284          // it is necessary to swap the resulting tangency points
285          invers = Standard_True;
286        }
287        if ((Radius-R1 > Tol) || (dist-R2-R1 > Tol)) { WellDone = Standard_True; }
288        else {
289          if ((Abs(dist-R2-R1) <= Tol) || (Abs(Radius-R1) <= Tol)) {
290            WellDone = Standard_True;
291            NbrSol = 1;
292            gp_Ax2d ax(gp_Pnt2d(center1.XY()+(R1-Radius)*dir1.XY()),dirx);
293            cirsol(1) = gp_Circ2d(ax,Radius);
294 //         ================================
295            qualifier1(1) = Qualified1.Qualifier();
296            qualifier2(1) = Qualified2.Qualifier();
297            pnttg2sol(1) = gp_Pnt2d(center1.XY()+(dist-R2)*dir1.XY());
298            TheSame2(1)  = 0;
299            if (Abs(Radius-R1) > 0.0) {
300              TheSame1(1)  = 1;
301            }
302            else {
303              TheSame1(1)  = 0;
304              pnttg1sol(1) = gp_Pnt2d(center1.XY()+R1*dir1.XY());
305            }
306          }
307          else {
308            C(3) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
309            C(4) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
310            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
311            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Abs(Radius-R2));
312            nbsol = 2;
313          }
314        }
315      }
316      else if ((Qualified1.IsEnclosing()) && (Qualified2.IsEnclosing())) {
317 //   ==================================================================
318        if ((Tol < Max(R1,R2)-Radius) || (Tol < Max(R1,R2)-dist-Min(R1,R2)) ||
319            (dist+R1+R2-Radius*2.0 > Tol)) { WellDone = Standard_True; }
320        else {
321          if ((Abs(dist+Min(R1,R2)-Max(R1,R2)) <= Tol) ||
322              (Abs(R1+R2+dist-2.0*Radius) <= Tol)) {
323            if (Abs(dist+Min(R1,R2)-Max(R1,R2)) <= Tol) {
324              signe = 1;
325            }
326            else {
327              signe = -1;
328            }
329            WellDone = Standard_True;
330            NbrSol = 1;
331            gp_Ax2d axe(gp_Pnt2d(center1.XY()+
332                                 signe*(R1-Radius)*dir1.XY()),dirx);
333            cirsol(1) = gp_Circ2d(axe,Radius);
334 //         =================================
335            qualifier1(1) = Qualified1.Qualifier();
336            qualifier2(1) = Qualified2.Qualifier();
337            pnttg1sol(1) = gp_Pnt2d(center1.XY()+R1*dir1.XY());
338            pnttg2sol(1) = gp_Pnt2d(center2.XY()+signe*R2*dir1.XY());
339            TheSame1(1)  = 0;
340            TheSame2(1)  = 0;
341          }
342          else if (Abs(Radius-Max(R1,R2)) <= Tol) {
343            WellDone = Standard_True;
344            NbrSol = 1;
345            if (R1 > R2) {
346              C(1) = gp_Circ2d(C1);
347              C(2) = gp_Circ2d(C2);
348              TheSame1(1) = 1;
349              TheSame2(1) = 0;
350              pnttg2sol(1) = gp_Pnt2d(center1.XY()+(dist+R2)*dir1.XY());
351            }
352            else {
353              C(1) = gp_Circ2d(C2);
354              C(2) = gp_Circ2d(C1);
355              TheSame1(1) = 0;
356              TheSame2(1) = 1;
357              pnttg1sol(1) = gp_Pnt2d(center1.XY()-R1*dir1.XY());
358            }
359            gp_Ax2d axe(C(1).Location(),dirx);
360            cirsol(1) = gp_Circ2d(axe,Radius);
361 //         =================================
362            qualifier1(1) = Qualified1.Qualifier();
363            qualifier2(1) = Qualified2.Qualifier();
364          }
365          else {
366            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
367            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Abs(Radius-R2));
368            nbsol = 1;
369          }
370        }
371      }
372      else if (((Qualified1.IsEnclosing()) && (Qualified2.IsOutside())) ||
373 //   ====================================================================
374               ((Qualified1.IsOutside()) && (Qualified2.IsEnclosing()))) {
375 //            =========================================================
376        if (Qualified1.IsOutside()) {
377          C(1) = gp_Circ2d(C2);
378          C(2) = gp_Circ2d(C1);
379          R3 = R1;
380          R1 = R2;
381          R2 = R3;
382          center3 = center1;
383          center1 = center2;
384          center2 = center3;
385          dir1.Reverse();
386          // it is necessary to swap the resulting tangency points 
387          invers = Standard_True;
388        }
389        if ((R1-Radius > Tol) || (Tol < R1+R2-dist) ||
390            (dist-R2+R1-Radius*2.0>Tol)) {
391          WellDone = Standard_True;
392        }
393        else if (((Abs(R1-Radius)<=Tol) || (Abs(R1+R2-dist)<=Tol))||
394                 (Abs(dist-R2+R1-Radius*2.0) <= Tol)) {
395          WellDone = Standard_True;
396          NbrSol = 1;
397          if((Abs(R1-Radius) <= Tol) || (Abs(R1+R2-dist) <= Tol)){
398            TheSame1(1) = 1;
399          }
400          else {
401            TheSame1(1) = 0;
402          }
403          TheSame2(1) = 0;
404          gp_Ax2d axe(gp_Pnt2d(center1.XY()+(R1-Radius)*dir1.XY()),dirx);
405          cirsol(1) = gp_Circ2d(axe,Radius);
406 //       =================================
407          qualifier1(1) = Qualified1.Qualifier();
408          qualifier2(1) = Qualified2.Qualifier();
409          pnttg1sol(1) = gp_Pnt2d(center1.XY()-R1*dir1.XY());
410          pnttg2sol(1) = gp_Pnt2d(center1.XY()+(dist-R2)*dir1.XY());
411        }
412        else {
413          C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
414          C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
415          nbsol = 1;
416        }
417      }
418      else if (((Qualified1.IsEnclosing()) && (Qualified2.IsUnqualified())) ||
419 //   ========================================================================
420               ((Qualified1.IsUnqualified()) && (Qualified2.IsEnclosing()))) {
421 //            =============================================================
422        if (Qualified1.IsUnqualified()) {
423          C(1) = gp_Circ2d(C2);
424          C(2) = gp_Circ2d(C1);
425          R3 = R1;
426          R1 = R2;
427          R2 = R3;
428          center3 = center1;
429          center1 = center2;
430          center2 = center3;
431          invers = Standard_True;
432          dir1.Reverse();
433        }
434        if ((Tol < R1-dist-R2) || (R1-Radius > Tol)) { WellDone = Standard_True; }
435        else if ((Abs(R1-Radius) <= Tol) || (Abs(R1-dist-R2) > 0.0)) {
436          if (Abs(R1-Radius) <= Tol) {
437            TheSame1(1) = 1;
438            if((Abs(Radius-R2) <= Tol) && 
439               (center1.Distance(center2) <= Tol)) {
440              TheSame2(1) = 1;
441            }
442          }
443          else if (Abs(R1-dist-R2) > 0.0) {
444            TheSame1(1)  = 0;
445            TheSame2(1)  = 0;
446          }
447          WellDone = Standard_True;
448          NbrSol = 1;
449          gp_Ax2d axe(gp_Pnt2d(center1.XY()+(Radius-R1)*dir1.XY()),dirx);
450          cirsol(1) = gp_Circ2d(axe,Radius);
451 //       =================================
452          qualifier1(1) = Qualified1.Qualifier();
453          qualifier2(1) = Qualified2.Qualifier();
454          pnttg1sol(1) = gp_Pnt2d(center1.XY()+R1*dir1.XY());
455          pnttg2sol(1) = gp_Pnt2d(center1.XY()+(dist+R2)*dir1.XY());
456        }
457        else {
458          C(3) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
459          C(4) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
460          C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R1));
461          C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Abs(Radius-R2));
462          nbsol    = 2;
463        }
464      }
465      else if ((Qualified1.IsOutside()) && (Qualified2.IsOutside())) {
466 //   ==============================================================
467        if (Tol < Max(R1,R2)-dist-Min(R1,R2)) { WellDone = Standard_True; }
468        else if (dist-R1-R2-Radius*2.0 > Tol) { WellDone = Standard_True; }
469        else {
470          if (Abs(dist+Min(R1,R2)-Max(R1,R2)) <= Tol) {
471            WellDone = Standard_True;
472            NbrSol = 1;
473            if (R1 < R2) { signe = -1; }
474            else { signe = 1; }
475            gp_Ax2d axe(gp_Pnt2d(center1.XY()+signe*(Radius+R1)*dir1.XY()),
476                        dirx);
477            cirsol(1) = gp_Circ2d(axe,Radius);
478 //         =================================
479            qualifier1(1) = Qualified1.Qualifier();
480            qualifier2(1) = Qualified2.Qualifier();
481            pnttg1sol(1) = gp_Pnt2d(center1.XY()+signe*R1*dir1.XY());
482            pnttg2sol(1) = gp_Pnt2d(pnttg1sol(1));
483            TheSame1(1)  = 0;
484            TheSame2(1)  = 0;
485          }
486          else if (Abs(dist-R1-R2-Radius*2.0) <= Tol) {
487            WellDone = Standard_True;
488            NbrSol = 1;
489            gp_Ax2d ax(gp_Pnt2d(center1.XY()+(R1+Radius)*dir1.XY()),dirx);
490            cirsol(1) = gp_Circ2d(ax,Radius);
491 //         ================================
492            qualifier1(1) = Qualified1.Qualifier();
493            qualifier2(1) = Qualified2.Qualifier();
494            pnttg1sol(1) = gp_Pnt2d(center1.XY()+R1*dir1.XY());
495            pnttg2sol(1) = gp_Pnt2d(center2.XY()-R2*dir1.XY());
496            TheSame1(1)  = 0;
497            TheSame2(1)  = 0;
498          }
499          else {
500            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Radius+R1);
501            C(2) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
502            nbsol    = 1;
503          }
504        }
505      }
506      else if (((Qualified1.IsOutside()) && (Qualified2.IsUnqualified())) ||
507 //   ======================================================================
508               ((Qualified1.IsUnqualified()) && (Qualified2.IsOutside()))) {
509 //            ===========================================================
510        if (Qualified1.IsUnqualified()) {
511          C(1) = gp_Circ2d(C2);
512          R3 = R1;
513          R1 = R2;
514          C(2) = gp_Circ2d(C1);
515          R2 = R3;
516          center3 = center1;
517          center1 = center2;
518          center2 = center3;
519          dir1.Reverse();
520          // it is necessary to swap the resulting tangency points
521          invers = Standard_True;
522        }
523        if (Tol < R1-dist-R2) { WellDone = Standard_True; }
524        else if ((Tol < R2-dist-R1) && (Tol < Radius*2.0-R2-dist+R1)) {
525          WellDone = Standard_True;
526        }
527        else if ((dist-R1-R2 > Tol) && (Tol < dist-R1-R2-Radius*2.0)) {
528          WellDone = Standard_True;
529        }
530        else {
531          if ((Abs(R1-R2-dist)<=Tol) || 
532              ((Abs(dist-R1-R2)<=Tol) && (Abs(Radius*2.0-dist+R1+R2) <= Tol)) ||
533              ((Abs(dist+R1-R2)<=Tol) && (Abs(R2+dist-R1-Radius*2.0)<=Tol))) {
534            WellDone = Standard_True;
535            NbrSol = 1;
536            gp_Ax2d axe(gp_Pnt2d(center1.XY()+(Radius+R1)*dir1.XY()),
537                        dirx);
538            cirsol(1) = gp_Circ2d(axe,Radius);
539 //         =================================
540            qualifier1(1) = Qualified1.Qualifier();
541            qualifier2(1) = Qualified2.Qualifier();
542            pnttg1sol(1) = gp_Pnt2d(center1.XY()+R1*dir1.XY());
543            pnttg2sol(1) = gp_Pnt2d(center1.XY()+(dist+R2)*dir1.XY());
544            TheSame1(1)  = 0;
545            TheSame2(1)  = 0;
546          }
547          else {
548            C(3) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Radius+R1);
549            C(4) = gp_Circ2d(gp_Ax2d(C(2).Location(),dirx),Radius+R2);
550            C(1) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Radius+R1);
551            C(2) = gp_Circ2d(gp_Ax2d(C(1).Location(),dirx),Abs(Radius-R2));
552            nbsol    = 2;
553          }
554        }
555      }
556      else if ((Qualified1.IsUnqualified()) && (Qualified2.IsUnqualified())) {
557 //   ======================================================================
558        if ((dist-R1-R2>Tol)&&(Tol<(dist-R1-R2-Radius*2))) { 
559          WellDone = Standard_True; 
560        }
561        else if ((Max(R1,R2)-dist-Min(R1,R2)>Tol) &&
562                 (((Max(R1,R2)-dist-Min(R1,R2))-Radius*2.0 > Tol))) {
563          WellDone = Standard_True;
564        }
565        else {
566          Standard_Real p3 = Max(R1,R2)-Min(R1,R2)-dist-Radius*2.0;
567          Standard_Real p4 = dist-R1-R2;
568          Standard_Real p5 = Radius*2.0-dist+R1+R2;
569          if (p3 > 0.0) {
570            dist = Max(R1,R2)-Min(R1,R2)-Radius*2.0;
571          }
572          else if (p4 > 0.0 && p5 < 0.0) {
573            R1 = dist-R2-Radius*2.0;
574          }
575          C(1) = gp_Circ2d(gp_Ax2d(center1,dirx),Abs(Radius-R1));
576          C(2) = gp_Circ2d(gp_Ax2d(center2,dirx),Abs(Radius-R2));
577          C(3) = gp_Circ2d(gp_Ax2d(center1,dirx),Abs(Radius-R1));
578          C(4) = gp_Circ2d(gp_Ax2d(center2,dirx),Radius+R2);
579          C(5) = gp_Circ2d(gp_Ax2d(center1,dirx),Radius+R1);
580          C(6) = gp_Circ2d(gp_Ax2d(center2,dirx),Abs(Radius-R2));
581          C(7) = gp_Circ2d(gp_Ax2d(center1,dirx),Radius+R1);
582          C(8) = gp_Circ2d(gp_Ax2d(center2,dirx),Radius+R2);
583          nbsol    = 4;
584        }
585      }
586      if (nbsol > 0) {
587        for (Standard_Integer j = 1 ; j <= nbsol ; j++) {
588          IntAna2d_AnaIntersection Intp(C(2*j-1),C(2*j));
589          if (Intp.IsDone()) {
590            if (!Intp.IsEmpty()) {
591              for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
592                NbrSol++;
593                gp_Pnt2d Center(Intp.Point(i).Value());
594                cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
595 //             =======================================================
596                dir1 = gp_Dir2d(Center.XY()-center1.XY());
597                gp_Dir2d dir2(Center.XY()-center2.XY());
598                Standard_Real distcc1 = Center.Distance(center1);
599                Standard_Real distcc2 = Center.Distance(center2);
600                if (!Qualified1.IsUnqualified()) { 
601                  qualifier1(NbrSol) = Qualified1.Qualifier();
602                }
603                else if (Abs(distcc1+Radius-R1) < Tol) {
604                  qualifier1(NbrSol) = GccEnt_enclosed;
605                }
606                else if (Abs(distcc1-R1-Radius) < Tol) {
607                  qualifier1(NbrSol) = GccEnt_outside;
608                }
609                else { qualifier1(NbrSol) = GccEnt_enclosing; }
610                if (!Qualified2.IsUnqualified()) { 
611                  qualifier2(NbrSol) = Qualified2.Qualifier();
612                }
613                else if (Abs(distcc2+Radius-R2) < Tol) {
614                  qualifier2(NbrSol) = GccEnt_enclosed;
615                }
616                else if (Abs(distcc2-R2-Radius) < Tol) {
617                  qualifier2(NbrSol) = GccEnt_outside;
618                }
619                else { qualifier2(NbrSol) = GccEnt_enclosing; }
620                if ((Center.Distance(center1) > R1) &&
621                    (Radius < Center.Distance(center1)+R1)) {
622                  pnttg1sol(NbrSol) = gp_Pnt2d(Center.XY()-Radius*dir1.XY());
623                }
624                else if ((Center.Distance(center1) < R1) &&
625                    (Radius < R1)) {
626                  pnttg1sol(NbrSol) = gp_Pnt2d(Center.XY()+Radius*dir1.XY());
627                }
628                else {
629                  pnttg1sol(NbrSol) = gp_Pnt2d(Center.XY()-Radius*dir1.XY());
630                }
631                if ((Center.Distance(center2) > R2) &&
632                    (Radius < Center.Distance(center2)+R2)) {
633                  pnttg2sol(NbrSol) = gp_Pnt2d(Center.XY()-Radius*dir2.XY());
634                }
635                else if ((Center.Distance(center2) < R2) &&
636                    (Radius < R2)) {
637                  pnttg2sol(NbrSol) = gp_Pnt2d(Center.XY()+Radius*dir2.XY());
638                }
639                else {
640                  pnttg2sol(NbrSol) = gp_Pnt2d(Center.XY()-Radius*dir2.XY());
641                }
642                TheSame1(NbrSol)  = 0;
643                TheSame2(NbrSol)  = 0;
644              }
645            }
646            WellDone = Standard_True;
647          }
648        }
649      }
650    }
651    // swapping of resulting tangency points if necessary
652    if (invers) {
653      gp_Pnt2d Psav;
654      for (Standard_Integer i = 1 ; i <= NbrSol ; i++) {
655        Psav = pnttg1sol(i);
656        pnttg1sol(i) = pnttg2sol(i);
657        pnttg2sol(i) = Psav;
658      }
659    }
660    // calculation of parameters of tangency points
661    for (Standard_Integer i = 1 ; i <= NbrSol ; i++) {
662      par1sol(i)=ElCLib::Parameter(cirsol(i),pnttg1sol(i));
663      if (TheSame1(i) == 0) {
664        pararg1(i)=ElCLib::Parameter(C1,pnttg1sol(i));
665      }
666      par2sol(i)=ElCLib::Parameter(cirsol(i),pnttg2sol(i));
667      if (TheSame2(i) == 0) {
668        pararg2(i)=ElCLib::Parameter(C2,pnttg2sol(i));
669      }
670    }
671  }
672
673 Standard_Boolean GccAna_Circ2d2TanRad::
674    IsDone () const { return WellDone; }
675
676 Standard_Integer GccAna_Circ2d2TanRad::
677    NbSolutions () const { return NbrSol; }
678
679 gp_Circ2d GccAna_Circ2d2TanRad::
680    ThisSolution (const Standard_Integer Index) const 
681 {
682   if (!WellDone) { StdFail_NotDone::Raise(); }
683   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
684   return cirsol(Index);
685 }
686
687 void GccAna_Circ2d2TanRad::
688   WhichQualifier(const Standard_Integer Index   ,
689                        GccEnt_Position& Qualif1 ,
690                        GccEnt_Position& Qualif2 ) const
691 {
692   if (!WellDone) { StdFail_NotDone::Raise(); }
693   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
694   
695   Qualif1 = qualifier1(Index);
696   Qualif2 = qualifier2(Index);
697 }
698
699 void GccAna_Circ2d2TanRad::
700    Tangency1 (const Standard_Integer Index,
701               Standard_Real& ParSol,
702               Standard_Real& ParArg,
703               gp_Pnt2d& PntSol) const{
704    if (!WellDone) { StdFail_NotDone::Raise(); }
705    else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
706    else {
707      if (TheSame1(Index) == 0) {
708        ParSol = par1sol(Index);
709        ParArg = pararg1(Index);
710        PntSol = gp_Pnt2d(pnttg1sol(Index));
711      }
712      else { StdFail_NotDone::Raise(); }
713    }
714  }
715
716 void GccAna_Circ2d2TanRad::
717    Tangency2 (const Standard_Integer Index,
718               Standard_Real& ParSol,
719               Standard_Real& ParArg,
720               gp_Pnt2d& PntSol) const{
721    if (!WellDone) { StdFail_NotDone::Raise(); }
722    else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
723    else {
724      if (TheSame2(Index) == 0) {
725        ParSol = par2sol(Index);
726        ParArg = pararg2(Index);
727        PntSol = gp_Pnt2d(pnttg2sol(Index));
728      }
729      else { StdFail_NotDone::Raise(); }
730    }
731  }
732
733 Standard_Boolean GccAna_Circ2d2TanRad::
734    IsTheSame1 (const Standard_Integer Index) const
735 {
736   if (!WellDone) { StdFail_NotDone::Raise(); }
737   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
738
739   if (TheSame1(Index) == 0) { return Standard_False; }
740   
741   return Standard_True;
742 }
743
744 Standard_Boolean GccAna_Circ2d2TanRad::
745    IsTheSame2 (const Standard_Integer Index) const
746 {
747   if (!WellDone) { StdFail_NotDone::Raise(); }
748   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
749   
750   if (TheSame2(Index) == 0) { return Standard_False; }
751   return Standard_True; 
752 }