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