0024303: Precision degradation for Geom2dGcc_Circ2d2TanRad in OCCT6.6.0.
authornbv <nbv@opencascade.com>
Thu, 14 Nov 2013 07:11:29 +0000 (11:11 +0400)
committerbugmaster <bugmaster@opencascade.com>
Thu, 14 Nov 2013 07:12:40 +0000 (11:12 +0400)
1. DRAW-command.
2. Initial point (the center of found circle), which is found by standard algorithm, is precised in function PrecRoot(...). Correction is called, if and only if initial point is in tangent zone.
3. Handling of possible divergences and of possible exceptions in PrecRoot() function is added.

Test cases for issue CR24303

src/GccGeo/GccGeo_Circ2d2TanRad.gxx
src/QABugs/QABugs_9.cxx
tests/bugs/modalg_5/bug24303 [new file with mode: 0755]

index b7ac235..71ba7dd 100755 (executable)
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
-   GccGeo_Circ2d2TanRad (const GccEnt_QualifiedLin&  Qualified1,
-                        const TheQCurve&            Qualified2,
-                        const Standard_Real         Radius    ,
-                        const Standard_Real         Tolerance ):
+GccGeo_Circ2d2TanRad (const GccEnt_QualifiedLin&  Qualified1,
+                      const TheQCurve&            Qualified2,
+                      const Standard_Real         Radius    ,
+                      const Standard_Real         Tolerance ):
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
-   cirsol(1,16)   ,
-   qualifier1(1,16),
-   qualifier2(1,16),
-   TheSame1(1,16) ,
-   TheSame2(1,16) ,
-   pnttg1sol(1,16),
-   pnttg2sol(1,16),
-   par1sol(1,16)  ,
-   par2sol(1,16)  ,
-   pararg1(1,16)  ,
-   pararg2(1,16)  
+cirsol(1,16)   ,
+qualifier1(1,16),
+qualifier2(1,16),
+TheSame1(1,16) ,
+TheSame2(1,16) ,
+pnttg1sol(1,16),
+pnttg2sol(1,16),
+par1sol(1,16)  ,
+par2sol(1,16)  ,
+pararg1(1,16)  ,
+pararg2(1,16)  
 {
 
 {
 
-//========================================================================
-// Traitement.                                                           +
-//========================================================================
-
-   Standard_Real Tol = Abs(Tolerance);
-   Standard_Real thefirst = -100000.;
-   Standard_Real thelast  =  100000.;
-   Standard_Real firstparam;
-   Standard_Real lastparam;
-   gp_Dir2d dirx(1.,0.);
-   TColStd_Array1OfReal cote1(1,2);
-   TColStd_Array1OfReal cote2(1,2);
-   Standard_Integer nbrcote1=0;
-   Standard_Integer nbrcote2=0;
-   WellDone = Standard_False;
-   NbrSol = 0;
-   if (!(Qualified1.IsEnclosed() ||
-        Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
-       !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
-        Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
-
-     GccEnt_BadQualifier::Raise();
-     return;
-   }
-   gp_Lin2d L1 = Qualified1.Qualified();
-   Standard_Real x1dir = (L1.Direction()).X();
-   Standard_Real y1dir = (L1.Direction()).Y();
-   Standard_Real lxloc = (L1.Location()).X();
-   Standard_Real lyloc = (L1.Location()).Y();
-   gp_Pnt2d origin1(lxloc,lyloc);
-   gp_Dir2d normL1(-y1dir,x1dir);
-   TheCurve Cu2= Qualified2.Qualified();
-   if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
-   else {
-     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
-//   =======================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
-//   ==========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = -Radius;
-     }
-     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
-//   ===========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = -Radius;
-     }
-     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
-//   =========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
-//   =============================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
-//   ========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = -Radius;
-     }
-     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
-//   =================================================================
-       nbrcote1 = 2;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     gp_Dir2d Dir(-y1dir,x1dir);
-     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
-       gp_Pnt2d Point(L1.Location().XY()+cote1(jcote1)*Dir.XY());
-       gp_Lin2d Line(Point,L1.Direction()); // ligne avec deport.
-       IntRes2d_Domain D1;
-       for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
-        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
-        TheParGenCurve C2(HCu2,cote2(jcote2));
-        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
-        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
-        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
-                           TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
-        TheIntConicCurve Intp(Line,D1,C2,D2,Tol,Tol);
-        if (Intp.IsDone()) {
-          if (!Intp.IsEmpty()) {
-            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
-              NbrSol++;
-              gp_Pnt2d Center(Intp.Point(i).Value());
-              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
-//             =======================================================
-              gp_Dir2d dc1(origin1.XY()-Center.XY());
-              qualifier2(NbrSol) = Qualified2.Qualifier();
-              if (!Qualified1.IsUnqualified()) { 
-                qualifier1(NbrSol) = Qualified1.Qualifier();
-              }
-              else if (dc1.Dot(normL1) > 0.0) {
-                qualifier1(NbrSol) = GccEnt_outside;
-              }
-              else { qualifier1(NbrSol) = GccEnt_enclosed; }
-              TheSame1(NbrSol) = 0;
-              TheSame2(NbrSol) = 0;
-              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
-              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
-              pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),L1);
-              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
-              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg1sol(NbrSol));
-              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg2sol(NbrSol));
-            }
-          }
-          WellDone = Standard_True;
-        }
-       }
-     }
-   }
- }
+  //========================================================================
+  // Traitement.                                                           +
+  //========================================================================
+
+  Standard_Real Tol = Abs(Tolerance);
+  Standard_Real thefirst = -100000.;
+  Standard_Real thelast  =  100000.;
+  Standard_Real firstparam;
+  Standard_Real lastparam;
+  gp_Dir2d dirx(1.,0.);
+  TColStd_Array1OfReal cote1(1,2);
+  TColStd_Array1OfReal cote2(1,2);
+  Standard_Integer nbrcote1=0;
+  Standard_Integer nbrcote2=0;
+  WellDone = Standard_False;
+  NbrSol = 0;
+  if (!(Qualified1.IsEnclosed() ||
+    Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
+    !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
+    Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
+
+      GccEnt_BadQualifier::Raise();
+      return;
+  }
+  gp_Lin2d L1 = Qualified1.Qualified();
+  Standard_Real x1dir = (L1.Direction()).X();
+  Standard_Real y1dir = (L1.Direction()).Y();
+  Standard_Real lxloc = (L1.Location()).X();
+  Standard_Real lyloc = (L1.Location()).Y();
+  gp_Pnt2d origin1(lxloc,lyloc);
+  gp_Dir2d normL1(-y1dir,x1dir);
+  TheCurve Cu2= Qualified2.Qualified();
+  if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
+  else {
+    if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
+      //   =======================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
+      //   ==========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = -Radius;
+    }
+    else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
+      //   ===========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = -Radius;
+    }
+    if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
+      //   =========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
+      //   =============================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
+      //   ========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = -Radius;
+    }
+    else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
+      //   =================================================================
+      nbrcote1 = 2;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    gp_Dir2d Dir(-y1dir,x1dir);
+    for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
+      gp_Pnt2d Point(L1.Location().XY()+cote1(jcote1)*Dir.XY());
+      gp_Lin2d Line(Point,L1.Direction()); // ligne avec deport.
+      IntRes2d_Domain D1;
+      for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
+        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
+        TheParGenCurve C2(HCu2,cote2(jcote2));
+        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
+        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
+        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
+          TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
+        TheIntConicCurve Intp(Line,D1,C2,D2,Tol,Tol);
+        if (Intp.IsDone()) {
+          if (!Intp.IsEmpty()) {
+            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
+              NbrSol++;
+              gp_Pnt2d Center(Intp.Point(i).Value());
+              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
+              //             =======================================================
+              gp_Dir2d dc1(origin1.XY()-Center.XY());
+              qualifier2(NbrSol) = Qualified2.Qualifier();
+              if (!Qualified1.IsUnqualified()) { 
+                qualifier1(NbrSol) = Qualified1.Qualifier();
+              }
+              else if (dc1.Dot(normL1) > 0.0) {
+                qualifier1(NbrSol) = GccEnt_outside;
+              }
+              else { qualifier1(NbrSol) = GccEnt_enclosed; }
+              TheSame1(NbrSol) = 0;
+              TheSame2(NbrSol) = 0;
+              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
+              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
+              pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),L1);
+              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
+              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg1sol(NbrSol));
+              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg2sol(NbrSol));
+            }
+          }
+          WellDone = Standard_True;
+        }
+      }
+    }
+  }
+}
 
 // circulaire tant a une courbe et un cercle ,de rayon donne
 //=============================================================
 
 // circulaire tant a une courbe et un cercle ,de rayon donne
 //=============================================================
@@ -232,183 +232,183 @@ GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
-   GccGeo_Circ2d2TanRad (const GccEnt_QualifiedCirc& Qualified1,
-                        const TheQCurve&            Qualified2,
-                        const Standard_Real         Radius    ,
-                        const Standard_Real         Tolerance ):
+GccGeo_Circ2d2TanRad (const GccEnt_QualifiedCirc& Qualified1,
+                      const TheQCurve&            Qualified2,
+                      const Standard_Real         Radius    ,
+                      const Standard_Real         Tolerance ):
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
-   cirsol(1,16)   ,
-   qualifier1(1,16),
-   qualifier2(1,16),
-   TheSame1(1,16) ,
-   TheSame2(1,16) ,
-   pnttg1sol(1,16),
-   pnttg2sol(1,16),
-   par1sol(1,16)  ,
-   par2sol(1,16)  ,
-   pararg1(1,16)  ,
-   pararg2(1,16)  
+cirsol(1,16)   ,
+qualifier1(1,16),
+qualifier2(1,16),
+TheSame1(1,16) ,
+TheSame2(1,16) ,
+pnttg1sol(1,16),
+pnttg2sol(1,16),
+par1sol(1,16)  ,
+par2sol(1,16)  ,
+pararg1(1,16)  ,
+pararg2(1,16)  
 {
 
 {
 
-//========================================================================
-// Traitement.                                                           +
-//========================================================================
-
-   Standard_Real Tol = Abs(Tolerance);
-   Standard_Real thefirst = -100000.;
-   Standard_Real thelast  =  100000.;
-   Standard_Real firstparam;
-   Standard_Real lastparam;
-   gp_Dir2d dirx(1.,0.);
-   TColStd_Array1OfReal cote1(1,2);
-   TColStd_Array1OfReal cote2(1,2);
-   Standard_Integer nbrcote1=0;
-   Standard_Integer nbrcote2=0;
-   WellDone = Standard_False;
-   NbrSol = 0;
-   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
-        Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
-       !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
-        Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
-     GccEnt_BadQualifier::Raise();
-     return;
-   }
-   gp_Circ2d C1 = Qualified1.Qualified();
-   gp_Pnt2d center1(C1.Location());
-   TheCurve Cu2 = Qualified2.Qualified();
-   if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
-   else {
-     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
-//   =======================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
-//   ==========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = -Radius;
-     }
-     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
-//   ===========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = -Radius;
-     }
-     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
-//   =========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
-//   =============================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
-//   ========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = -Radius;
-     }
-     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
-//   =================================================================
-       nbrcote1 = 2;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     Standard_Real R1 = C1.Radius();
-     TheIntConicCurve Intp;
-     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
-       gp_Circ2d Circ(C1.XAxis(),R1+cote1(jcote1));
-       IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
-                         ElCLib::Value(2.*M_PI,Circ),2.*M_PI,Tol);
-       D1.SetEquivalentParameters(0.,2.*M_PI);
-       for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
-        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
-        TheParGenCurve C2(HCu2,cote2(jcote2));
-        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
-        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
-        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
-                           TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
-        Intp.Perform(Circ,D1,C2,D2,Tol,Tol);
-        if (Intp.IsDone()) {
-          if (!Intp.IsEmpty()) {
-            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
-              NbrSol++;
-              gp_Pnt2d Center(Intp.Point(i).Value());
-              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
-//             =======================================================
+  //========================================================================
+  // Traitement.                                                           +
+  //========================================================================
+
+  Standard_Real Tol = Abs(Tolerance);
+  Standard_Real thefirst = -100000.;
+  Standard_Real thelast  =  100000.;
+  Standard_Real firstparam;
+  Standard_Real lastparam;
+  gp_Dir2d dirx(1.,0.);
+  TColStd_Array1OfReal cote1(1,2);
+  TColStd_Array1OfReal cote2(1,2);
+  Standard_Integer nbrcote1=0;
+  Standard_Integer nbrcote2=0;
+  WellDone = Standard_False;
+  NbrSol = 0;
+  if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
+    Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
+    !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
+    Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
+      GccEnt_BadQualifier::Raise();
+      return;
+  }
+  gp_Circ2d C1 = Qualified1.Qualified();
+  gp_Pnt2d center1(C1.Location());
+  TheCurve Cu2 = Qualified2.Qualified();
+  if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
+  else {
+    if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
+      //   =======================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
+      //   ==========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = -Radius;
+    }
+    else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
+      //   ===========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = -Radius;
+    }
+    if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
+      //   =========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
+      //   =============================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
+      //   ========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = -Radius;
+    }
+    else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
+      //   =================================================================
+      nbrcote1 = 2;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    Standard_Real R1 = C1.Radius();
+    TheIntConicCurve Intp;
+    for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
+      gp_Circ2d Circ(C1.XAxis(),R1+cote1(jcote1));
+      IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
+        ElCLib::Value(2.*M_PI,Circ),2.*M_PI,Tol);
+      D1.SetEquivalentParameters(0.,2.*M_PI);
+      for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
+        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
+        TheParGenCurve C2(HCu2,cote2(jcote2));
+        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
+        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
+        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
+          TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
+        Intp.Perform(Circ,D1,C2,D2,Tol,Tol);
+        if (Intp.IsDone()) {
+          if (!Intp.IsEmpty()) {
+            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
+              NbrSol++;
+              gp_Pnt2d Center(Intp.Point(i).Value());
+              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
+              //             =======================================================
 #ifdef DEB
 #ifdef DEB
-              gp_Dir2d dir1(Center.XY()-center1.XY());
+              gp_Dir2d dir1(Center.XY()-center1.XY());
 #else
 #else
-               Center.XY() ;
-               center1.XY() ;
+              Center.XY() ;
+              center1.XY() ;
 #endif
 #endif
-              Standard_Real distcc1 = Center.Distance(center1);
-              if (!Qualified1.IsUnqualified()) { 
-                qualifier1(NbrSol) = Qualified1.Qualifier();
-              }
-              else if (Abs(distcc1+Radius-R1) < Tol) {
-                qualifier1(NbrSol) = GccEnt_enclosed;
-              }
-              else if (Abs(distcc1-R1-Radius) < Tol) {
-                qualifier1(NbrSol) = GccEnt_outside;
-              }
-              else { qualifier1(NbrSol) = GccEnt_enclosing; }
-              qualifier2(NbrSol) = Qualified2.Qualifier();
-              TheSame1(NbrSol) = 0;
-              TheSame2(NbrSol) = 0;
-              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
-              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
-              pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),C1);
-              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
-              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg1sol(NbrSol));
-              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg2sol(NbrSol));
-            }
-          }
-          WellDone = Standard_True;
-        }
-       }
-     }
-   }
- }
+              Standard_Real distcc1 = Center.Distance(center1);
+              if (!Qualified1.IsUnqualified()) { 
+                qualifier1(NbrSol) = Qualified1.Qualifier();
+              }
+              else if (Abs(distcc1+Radius-R1) < Tol) {
+                qualifier1(NbrSol) = GccEnt_enclosed;
+              }
+              else if (Abs(distcc1-R1-Radius) < Tol) {
+                qualifier1(NbrSol) = GccEnt_outside;
+              }
+              else { qualifier1(NbrSol) = GccEnt_enclosing; }
+              qualifier2(NbrSol) = Qualified2.Qualifier();
+              TheSame1(NbrSol) = 0;
+              TheSame2(NbrSol) = 0;
+              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
+              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
+              pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),C1);
+              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
+              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg1sol(NbrSol));
+              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg2sol(NbrSol));
+            }
+          }
+          WellDone = Standard_True;
+        }
+      }
+    }
+  }
+}
 
 // circulaire tant a une courbe et un point ,de rayon donne
 //============================================================
 
 // circulaire tant a une courbe et un point ,de rayon donne
 //============================================================
@@ -425,105 +425,297 @@ GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
-   GccGeo_Circ2d2TanRad (const TheQCurve&    Qualified1,
-                        const gp_Pnt2d&     Point2    ,
-                        const Standard_Real Radius    ,
-                        const Standard_Real Tolerance ):
+GccGeo_Circ2d2TanRad (const TheQCurve&    Qualified1,
+                      const gp_Pnt2d&     Point2    ,
+                      const Standard_Real Radius    ,
+                      const Standard_Real Tolerance ):
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
-   cirsol(1,16)   ,
-   qualifier1(1,16),
-   qualifier2(1,16),
-   TheSame1(1,16) ,
-   TheSame2(1,16) ,
-   pnttg1sol(1,16),
-   pnttg2sol(1,16),
-   par1sol(1,16)  ,
-   par2sol(1,16)  ,
-   pararg1(1,16)  ,
-   pararg2(1,16)  
+cirsol(1,16)   ,
+qualifier1(1,16),
+qualifier2(1,16),
+TheSame1(1,16) ,
+TheSame2(1,16) ,
+pnttg1sol(1,16),
+pnttg2sol(1,16),
+par1sol(1,16)  ,
+par2sol(1,16)  ,
+pararg1(1,16)  ,
+pararg2(1,16)  
 {
 
 {
 
-//========================================================================
-// Traitement.                                                           +
-//========================================================================
+  //========================================================================
+  // Traitement.                                                           +
+  //========================================================================
+
+  Standard_Real Tol = Abs(Tolerance);
+  Standard_Real thefirst = -100000.;
+  Standard_Real thelast  =  100000.;
+  Standard_Real firstparam;
+  Standard_Real lastparam;
+  gp_Dir2d dirx(1.,0.);
+  TColStd_Array1OfReal cote1(1,2);
+  Standard_Integer nbrcote1=0;
+  WellDone = Standard_False;
+  NbrSol = 0;
+  if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
+    Qualified1.IsOutside() || Qualified1.IsUnqualified())) {
+      GccEnt_BadQualifier::Raise();
+      return;
+  }
+  TheCurve Cu1 = Qualified1.Qualified();
+  if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
+  else {
+    if (Qualified1.IsEnclosed()) {
+      //    ===========================
+      nbrcote1 = 1;
+      cote1(1) = Radius;
+    }
+    else if(Qualified1.IsOutside()) {
+      //   ===============================
+      nbrcote1 = 1;
+      cote1(1) = -Radius;
+    }
+    else if(Qualified1.IsUnqualified()) {
+      //   ===================================
+      nbrcote1 = 2;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+    }
+    gp_Circ2d Circ(gp_Ax2d(Point2,gp_Dir2d(1.,0.)),Radius);
+    IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
+      ElCLib::Value(M_PI+M_PI,Circ),M_PI+M_PI,Tol);
+    D1.SetEquivalentParameters(0.,M_PI+M_PI);
+    TheIntConicCurve Intp;
+    for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
+      Handle(TheHParGenCurve) HCu1 = new TheHParGenCurve(Cu1);
+      TheParGenCurve Cu2(HCu1,cote1(jcote1));
+      firstparam = Max(TheCurvePGTool::FirstParameter(Cu2),thefirst);
+      lastparam  = Min(TheCurvePGTool::LastParameter(Cu2),thelast);
+      IntRes2d_Domain D2(TheCurvePGTool::Value(Cu2,firstparam),firstparam,Tol,
+        TheCurvePGTool::Value(Cu2,lastparam),lastparam,Tol);
+      Intp.Perform(Circ,D1,Cu2,D2,Tol,Tol);
+      if (Intp.IsDone()) {
+        if (!Intp.IsEmpty()) {
+          for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
+            NbrSol++;
+            gp_Pnt2d Center(Intp.Point(i).Value());
+            cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
+            //           =======================================================
+            qualifier1(NbrSol) = Qualified1.Qualifier();
+            qualifier2(NbrSol) = GccEnt_noqualifier;
+            TheSame1(NbrSol) = 0;
+            TheSame2(NbrSol) = 0;
+            pararg1(NbrSol) = Intp.Point(i).ParamOnSecond();
+            pararg2(NbrSol) = 0.;
+            pnttg1sol(NbrSol) = TheTool::Value(Cu1,pararg1(NbrSol));
+            pnttg2sol(NbrSol) = Point2;
+            par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+              pnttg1sol(NbrSol));
+            par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+              pnttg2sol(NbrSol));
+          }
+        }
+        WellDone = Standard_True;
+      }
+    }
+  }
+}
+
+static void PrecRoot(const TheParGenCurve& theC1,
+                                 const TheParGenCurve& theC2,
+                                 const Standard_Real theU0,
+                                 const Standard_Real theV0,
+                                 const Standard_Real theUmin,
+                                 const Standard_Real theUmax,
+                                 const Standard_Real theVmin,
+                                 const Standard_Real theVmax,
+                                 Standard_Real& theUfinal,
+                                 Standard_Real& theVfinal)
+{
+  const Standard_Real aInitStepU = (theUmax - theUmin)/2.0,
+                      aInitStepV = (theVmax - theVmin)/2.0;
+
+  Standard_Real aStepU = aInitStepU, aStepV = aInitStepV;
+
+  const Standard_Real aTol = Precision::PConfusion() * Precision::PConfusion();
+  const Standard_Integer aNbIterMax = 100;
+
+  gp_Pnt2d aP1, aP2;
+  gp_Vec2d aD1, aD2;
+
+  TheCurvePGTool::D1(theC1, theU0, aP1, aD1);
+  TheCurvePGTool::D1(theC2, theV0, aP2, aD2);
+
+  gp_Vec2d vP12(aP1.XY() - aP2.XY());
+
+  Standard_Real aU = theU0, aV = theV0;
+  theUfinal = theU0;
+  theVfinal = theV0;
+
+  Standard_Real aSQDistPrev = aP1.SquareDistance(aP2);
+  
+  Standard_Integer aNbIter = 1;
+
+  do
+  {
+    Standard_Real aDetH = aD1.Y()*aD2.X() - aD1.X()*aD2.Y();
+    if(aDetH == 0.0)
+      break;
+
+    aU += aStepU*(aD2.Y() * vP12.X() - aD2.X()*vP12.Y())/aDetH;
+    aV += aStepV*(aD1.Y() * vP12.X() - aD1.X()*vP12.Y())/aDetH;
+
+    if(Abs(aU - theUmin) > 1000.0)
+      //method diverges
+      return;
+
+    if(Abs(aU - theUmax) > 1000.0)
+      //method diverges
+      return;
+
+    if(Abs(aV - theVmin) > 1000.0)
+      //method diverges
+      return;
+
+    if(Abs(aV - theVmax) > 1000.0)
+      //method diverges
+      return;
+
+    TheCurvePGTool::D1(theC1, aU, aP1, aD1);
+    TheCurvePGTool::D1(theC2, aV, aP2, aD2);
+    const Standard_Real aSQDist = aP1.SquareDistance(aP2);
+
+    if(Precision::IsInfinite(aSQDist))
+      //method diverges
+      return;
+
+    vP12.SetXY(aP1.XY() - aP2.XY());
+
+    if(aSQDist < aSQDistPrev)
+    {
+      aSQDistPrev = aSQDist;
+      aStepU = aInitStepU;
+      aStepV = aInitStepV;
+      theUfinal = aU;
+      theVfinal = aV;
+    }
+    else
+    {
+      aStepU /= 2.0;
+      aStepV /= 2.0;
+    }
+  }
+  while((aNbIter++ < aNbIterMax) && ((aStepU > aTol) || (aStepV > aTol)));
+
+  Standard_Boolean isInBound = Standard_True;
+  if(theUfinal < theUmin)
+  {
+    aU = theUfinal;
+    aV = theVfinal;
+
+    theUfinal = theUmin;
+    isInBound = Standard_False;
+  }
+
+  if(theUfinal > theUmax)
+  {
+    aU = theUfinal;
+    aV = theVfinal;
+
+    theUfinal = theUmax;
+    isInBound = Standard_False;
+  }
+
+  if(!isInBound)
+  {
+    TheCurvePGTool::D1(theC1, aU, aP1, aD1);
+    TheCurvePGTool::D1(theC2, aV, aP2, aD2);
+    Standard_Real aV1 = (aD2.X() == 0.0) ? aV :((theUfinal - aU)*aD1.X() + aV*aD2.X() + (aP1.X() - aP2.X()))/aD2.X();
+    Standard_Real aV2 = (aD2.Y() == 0.0) ? aV :((theUfinal - aU)*aD1.Y() + aV*aD2.Y() + (aP1.Y() - aP2.Y()))/aD2.Y();
+
+    if(aV1 < theVmin)
+      aV1 = theVmin;
+
+    if(aV1 > theVmax)
+      aV1 = theVmax;
+
+    if(aV2 < theVmin)
+      aV2 = theVmin;
 
 
-   Standard_Real Tol = Abs(Tolerance);
-   Standard_Real thefirst = -100000.;
-   Standard_Real thelast  =  100000.;
-   Standard_Real firstparam;
-   Standard_Real lastparam;
-   gp_Dir2d dirx(1.,0.);
-   TColStd_Array1OfReal cote1(1,2);
-   Standard_Integer nbrcote1=0;
-   WellDone = Standard_False;
-   NbrSol = 0;
-   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
-        Qualified1.IsOutside() || Qualified1.IsUnqualified())) {
-     GccEnt_BadQualifier::Raise();
-     return;
-   }
-   TheCurve Cu1 = Qualified1.Qualified();
-   if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
-   else {
-     if (Qualified1.IsEnclosed()) {
-//    ===========================
-       nbrcote1 = 1;
-       cote1(1) = Radius;
-     }
-     else if(Qualified1.IsOutside()) {
-//   ===============================
-       nbrcote1 = 1;
-       cote1(1) = -Radius;
-     }
-     else if(Qualified1.IsUnqualified()) {
-//   ===================================
-       nbrcote1 = 2;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-     }
-     gp_Circ2d Circ(gp_Ax2d(Point2,gp_Dir2d(1.,0.)),Radius);
-     IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
-                       ElCLib::Value(M_PI+M_PI,Circ),M_PI+M_PI,Tol);
-     D1.SetEquivalentParameters(0.,M_PI+M_PI);
-     TheIntConicCurve Intp;
-     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
-       Handle(TheHParGenCurve) HCu1 = new TheHParGenCurve(Cu1);
-       TheParGenCurve Cu2(HCu1,cote1(jcote1));
-       firstparam = Max(TheCurvePGTool::FirstParameter(Cu2),thefirst);
-       lastparam  = Min(TheCurvePGTool::LastParameter(Cu2),thelast);
-       IntRes2d_Domain D2(TheCurvePGTool::Value(Cu2,firstparam),firstparam,Tol,
-                         TheCurvePGTool::Value(Cu2,lastparam),lastparam,Tol);
-       Intp.Perform(Circ,D1,Cu2,D2,Tol,Tol);
-       if (Intp.IsDone()) {
-        if (!Intp.IsEmpty()) {
-          for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
-            NbrSol++;
-            gp_Pnt2d Center(Intp.Point(i).Value());
-            cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
-//           =======================================================
-            qualifier1(NbrSol) = Qualified1.Qualifier();
-            qualifier2(NbrSol) = GccEnt_noqualifier;
-            TheSame1(NbrSol) = 0;
-            TheSame2(NbrSol) = 0;
-            pararg1(NbrSol) = Intp.Point(i).ParamOnSecond();
-            pararg2(NbrSol) = 0.;
-            pnttg1sol(NbrSol) = TheTool::Value(Cu1,pararg1(NbrSol));
-            pnttg2sol(NbrSol) = Point2;
-            par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                             pnttg1sol(NbrSol));
-            par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                             pnttg2sol(NbrSol));
-          }
-        }
-        WellDone = Standard_True;
-       }
-     }
-   }
- }
+    if(aV2 > theVmax)
+      aV2 = theVmax;
+
+    aP1 = TheCurvePGTool::Value(theC1,theUfinal);
+    aP2 = TheCurvePGTool::Value(theC2,aV1);
+
+    Standard_Real aSQ1 = aP1.SquareDistance(aP2);
+
+    aP2 = TheCurvePGTool::Value(theC2,aV2);
+    Standard_Real aSQ2 = aP1.SquareDistance(aP2);
+
+    if(aSQ1 < aSQ2)
+      theVfinal = aV1;
+    else
+      theVfinal = aV2;
+
+    return;
+  }
+
+  if(theVfinal < theVmin)
+  {
+    aU = theUfinal;
+    aV = theVfinal;
+
+    theVfinal = theVmin;
+    isInBound = Standard_False;
+  }
+
+  if(theVfinal > theVmax)
+  {
+    aU = theUfinal;
+    aV = theVfinal;
+
+    theVfinal = theVmax;
+    isInBound = Standard_False;
+  }
+
+  if(isInBound)
+    return;
+
+  TheCurvePGTool::D1(theC1, aU, aP1, aD1);
+  TheCurvePGTool::D1(theC2, aV, aP2, aD2);
+  Standard_Real aU1 = (aD1.X() == 0.0) ? aU :((theVfinal - aV)*aD2.X() + aU*aD1.X() + (aP2.X() - aP1.X()))/aD1.X();
+  Standard_Real aU2 = (aD1.Y() == 0.0) ? aU :((theVfinal - aV)*aD2.Y() + aU*aD1.Y() + (aP2.Y() - aP1.Y()))/aD1.Y();
+
+  if(aU1 < theUmin)
+    aU1 = theUmin;
+
+  if(aU1 > theUmax)
+    aU1 = theUmax;
+
+  if(aU2 < theUmin)
+    aU2 = theUmin;
+
+  if(aU2 > theUmax)
+    aU2 = theUmax;
+
+  aP2 = TheCurvePGTool::Value(theC2,theVfinal);
+  aP1 = TheCurvePGTool::Value(theC1,aU1);
+
+  Standard_Real aSQ1 = aP1.SquareDistance(aP2);
+
+  aP1 = TheCurvePGTool::Value(theC1,aU2);
+  Standard_Real aSQ2 = aP1.SquareDistance(aP2);
+
+  if(aSQ1 < aSQ2)
+    theUfinal = aU1;
+  else
+    theUfinal = aU2;  
+}
 
 // circulaire tant a deux courbes ,de rayon donne
 //==================================================
 
 // circulaire tant a deux courbes ,de rayon donne
 //==================================================
@@ -540,188 +732,221 @@ GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
 //========================================================================
 
 GccGeo_Circ2d2TanRad::
-   GccGeo_Circ2d2TanRad (const TheQCurve&    Qualified1,
-                        const TheQCurve&    Qualified2,
-                        const Standard_Real Radius    ,
-                        const Standard_Real Tolerance ):
+GccGeo_Circ2d2TanRad (const TheQCurve&    Qualified1,
+                      const TheQCurve&    Qualified2,
+                      const Standard_Real Radius    ,
+                      const Standard_Real Tolerance ):
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
 
 //========================================================================
 // initialisation des champs.                                            +
 //========================================================================
 
-   cirsol(1,16)   ,
-   qualifier1(1,16),
-   qualifier2(1,16),
-   TheSame1(1,16) ,
-   TheSame2(1,16) ,
-   pnttg1sol(1,16),
-   pnttg2sol(1,16),
-   par1sol(1,16)  ,
-   par2sol(1,16)  ,
-   pararg1(1,16)  ,
-   pararg2(1,16)  
+cirsol(1,16)   ,
+qualifier1(1,16),
+qualifier2(1,16),
+TheSame1(1,16) ,
+TheSame2(1,16) ,
+pnttg1sol(1,16),
+pnttg2sol(1,16),
+par1sol(1,16)  ,
+par2sol(1,16)  ,
+pararg1(1,16)  ,
+pararg2(1,16)  
 {
 
 {
 
-//========================================================================
-// Traitement.                                                           +
-//========================================================================
-
-   Standard_Real Tol = Abs(Tolerance);
-   Standard_Real thefirst = -100000.;
-   Standard_Real thelast  =  100000.;
-   Standard_Real firstparam;
-   Standard_Real lastparam;
-   gp_Dir2d dirx(1.,0.);
-   TColStd_Array1OfReal cote1(1,2);
-   TColStd_Array1OfReal cote2(1,2);
-   Standard_Integer nbrcote1=0;
-   Standard_Integer nbrcote2=0;
-   WellDone = Standard_False;
-   NbrSol = 0;
-   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
-        Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
-       !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
-        Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
-     GccEnt_BadQualifier::Raise();
-     return;
-   }
-   TheCurve Cu1 = Qualified1.Qualified();
-   TheCurve Cu2 = Qualified2.Qualified();
-   if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
-   else {
-     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
-//   =======================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
-//   ==========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote2(1) = -Radius;
-     }
-     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
-//   ===========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 1;
-       cote1(1) = -Radius;
-       cote2(1) = -Radius;
-     }
-     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
-//   =========================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
-//   =========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-     }
-     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
-//   =============================================================
-       nbrcote1 = 1;
-       nbrcote2 = 2;
-       cote1(1) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
-//   ========================================================
-       nbrcote1 = 2;
-       nbrcote2 = 1;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = -Radius;
-     }
-     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
-//   =================================================================
-       nbrcote1 = 2;
-       nbrcote2 = 2;
-       cote1(1) = Radius;
-       cote1(2) = -Radius;
-       cote2(1) = Radius;
-       cote2(2) = -Radius;
-     }
-     TheIntCurveCurve Intp;
-     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
-       Handle(TheHParGenCurve) HCu1 = new TheHParGenCurve(Cu1); 
-       TheParGenCurve C1(HCu1,cote1(jcote1));
-       firstparam = Max(TheCurvePGTool::FirstParameter(C1),thefirst);
-       lastparam  = Min(TheCurvePGTool::LastParameter(C1),thelast);
+  //========================================================================
+  // Traitement.                                                           +
+  //========================================================================
+
+  Standard_Real Tol = Abs(Tolerance);
+  Standard_Real thefirst = -100000.;
+  Standard_Real thelast  =  100000.;
+  Standard_Real firstparam;
+  Standard_Real lastparam;
+  gp_Dir2d dirx(1.,0.);
+  TColStd_Array1OfReal cote1(1,2);
+  TColStd_Array1OfReal cote2(1,2);
+  Standard_Integer nbrcote1=0;
+  Standard_Integer nbrcote2=0;
+  WellDone = Standard_False;
+  NbrSol = 0;
+  if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
+    Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
+    !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
+    Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
+      GccEnt_BadQualifier::Raise();
+      return;
+  }
+  TheCurve Cu1 = Qualified1.Qualified();
+  TheCurve Cu2 = Qualified2.Qualified();
+  if (Radius < 0.0) { Standard_NegativeValue::Raise(); }
+  else {
+    if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
+      //   =======================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
+      //   ==========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote2(1) = -Radius;
+    }
+    else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
+      //   ===========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 1;
+      cote1(1) = -Radius;
+      cote2(1) = -Radius;
+    }
+    if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
+      //   =========================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
+      //   =========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+    }
+    else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
+      //   =============================================================
+      nbrcote1 = 1;
+      nbrcote2 = 2;
+      cote1(1) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
+      //   ========================================================
+      nbrcote1 = 2;
+      nbrcote2 = 1;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = -Radius;
+    }
+    else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
+      //   =================================================================
+      nbrcote1 = 2;
+      nbrcote2 = 2;
+      cote1(1) = Radius;
+      cote1(2) = -Radius;
+      cote2(1) = Radius;
+      cote2(2) = -Radius;
+    }
+    TheIntCurveCurve Intp;
+    for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
+      Handle(TheHParGenCurve) HCu1 = new TheHParGenCurve(Cu1); 
+      TheParGenCurve C1(HCu1,cote1(jcote1));
+      firstparam = Max(TheCurvePGTool::FirstParameter(C1),thefirst);
+      lastparam  = Min(TheCurvePGTool::LastParameter(C1),thelast);
 #ifdef DEB
 #ifdef DEB
-       IntRes2d_Domain D2(TheCurvePGTool::Value(C1,firstparam),firstparam,Tol,
-                         TheCurvePGTool::Value(C1,lastparam),lastparam,Tol);
+      IntRes2d_Domain D2(TheCurvePGTool::Value(C1,firstparam),firstparam,Tol,
+        TheCurvePGTool::Value(C1,lastparam),lastparam,Tol);
 #else
 #else
-       TheCurvePGTool::Value(C1,firstparam);
-       TheCurvePGTool::Value(C1,lastparam);
+      TheCurvePGTool::Value(C1,firstparam);
+      TheCurvePGTool::Value(C1,lastparam);
 #endif
 #endif
-       for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
-        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
-        TheParGenCurve C2(HCu2,cote2(jcote2));
-        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
-        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
+      for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
+        Handle(TheHParGenCurve) HCu2 = new TheHParGenCurve(Cu2);
+        TheParGenCurve C2(HCu2,cote2(jcote2));
+        firstparam = Max(TheCurvePGTool::FirstParameter(C2),thefirst);
+        lastparam  = Min(TheCurvePGTool::LastParameter(C2),thelast);
 #ifdef DEB
 #ifdef DEB
-        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
-                           TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
+        IntRes2d_Domain D2(TheCurvePGTool::Value(C2,firstparam),firstparam,Tol,
+          TheCurvePGTool::Value(C2,lastparam),lastparam,Tol);
 #else
 #else
-         TheCurvePGTool::Value(C2,firstparam);
-         TheCurvePGTool::Value(C2,lastparam);
+        TheCurvePGTool::Value(C2,firstparam);
+        TheCurvePGTool::Value(C2,lastparam);
 #endif
 #endif
-        Intp.Perform(C1,C2,Tol,Tol);
-        if (Intp.IsDone()) {
-          if (!Intp.IsEmpty()) {
-            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
-              NbrSol++;
-              gp_Pnt2d Center(Intp.Point(i).Value());
-              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
-//             =======================================================
-              qualifier1(NbrSol) = Qualified1.Qualifier();
-              qualifier1(NbrSol) = Qualified1.Qualifier();
-              TheSame1(NbrSol) = 0;
-              TheSame2(NbrSol) = 0;
-              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
-              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
-              pnttg1sol(NbrSol) = TheTool::Value(Cu1,pararg1(NbrSol));
-              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
-              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg1sol(NbrSol));
-              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
-                                               pnttg2sol(NbrSol));
-            }
-          }
-          WellDone = Standard_True;
-        }
-       }
-     }
-   }
- }
+        Intp.Perform(C1,C2,Tol,Tol);
+        if (Intp.IsDone()) {
+          if (!Intp.IsEmpty()) {
+            for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++)
+            {
+              Standard_Real aU0 = Intp.Point(i).ParamOnFirst();
+              Standard_Real aV0 = Intp.Point(i).ParamOnSecond();
+
+              Standard_Real aU1 = aU0-Precision::PApproximation();
+              Standard_Real aV1 = aV0-Precision::PApproximation();
+
+              Standard_Real aU2 = aU0+Precision::PApproximation();
+              Standard_Real aV2 = aV0+Precision::PApproximation();
+
+              gp_Pnt2d P11 = TheCurvePGTool::Value(C1,aU1);
+              gp_Pnt2d P12 = TheCurvePGTool::Value(C2,aV1);
+              gp_Pnt2d P21 = TheCurvePGTool::Value(C1,aU2);
+              gp_Pnt2d P22 = TheCurvePGTool::Value(C2,aV2);
+
+              Standard_Real aDist1112 = P11.Distance(P12);
+              Standard_Real aDist1122 = P11.Distance(P22);
+
+              Standard_Real aDist1221 = P12.Distance(P21);
+              Standard_Real aDist2122 = P21.Distance(P22);
+
+              if( Min(aDist1112, aDist1122) <= Precision::Approximation() &&
+                  Min(aDist1221, aDist2122) <= Precision::Approximation())
+              {
+                PrecRoot(C1, C2, aU0, aV0,
+                         Max(TheCurvePGTool::FirstParameter(C1), aU0 - 10.0),
+                         Min(TheCurvePGTool::LastParameter(C1), aU0 + 10.0),
+                         Max(TheCurvePGTool::FirstParameter(C2), aV0 - 10.0),
+                         Min(TheCurvePGTool::LastParameter(C2), aV0 + 10.0),
+                         aU0, aV0);
+              }
+
+              NbrSol++;
+              gp_Pnt2d Center(TheCurvePGTool::Value(C1, aU0));
+              cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
+              //             =======================================================
+              qualifier1(NbrSol) = Qualified1.Qualifier();
+              qualifier1(NbrSol) = Qualified1.Qualifier();
+              TheSame1(NbrSol) = 0;
+              TheSame2(NbrSol) = 0;
+              pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
+              pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
+              pnttg1sol(NbrSol) = TheTool::Value(Cu1,pararg1(NbrSol));
+              pnttg2sol(NbrSol) = TheTool::Value(Cu2,pararg2(NbrSol));
+              par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg1sol(NbrSol));
+              par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
+                pnttg2sol(NbrSol));
+            }
+          }
+
+          WellDone = Standard_True;
+        }
+      }
+    }
+  }
+}
 
 //=========================================================================
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
 
 //=========================================================================
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
-   IsDone () const { return WellDone; }
+IsDone () const { return WellDone; }
 
 Standard_Integer GccGeo_Circ2d2TanRad::
 
 Standard_Integer GccGeo_Circ2d2TanRad::
-   NbSolutions () const { return NbrSol; }
+NbSolutions () const { return NbrSol; }
 
 gp_Circ2d GccGeo_Circ2d2TanRad::
 
 gp_Circ2d GccGeo_Circ2d2TanRad::
-   ThisSolution (const Standard_Integer Index) const 
+ThisSolution (const Standard_Integer Index) const 
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
@@ -729,9 +954,9 @@ gp_Circ2d GccGeo_Circ2d2TanRad::
 }
 
 void GccGeo_Circ2d2TanRad::
 }
 
 void GccGeo_Circ2d2TanRad::
-  WhichQualifier(const Standard_Integer Index   ,
-                      GccEnt_Position& Qualif1 ,
-                      GccEnt_Position& Qualif2 ) const
+WhichQualifier(const Standard_Integer Index   ,
+               GccEnt_Position& Qualif1 ,
+               GccEnt_Position& Qualif2 ) const
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
@@ -742,41 +967,41 @@ void GccGeo_Circ2d2TanRad::
 }
 
 void GccGeo_Circ2d2TanRad::
 }
 
 void GccGeo_Circ2d2TanRad::
-   Tangency1 (const Standard_Integer Index,
-                 Standard_Real&   ParSol,
-                 Standard_Real&   ParArg,
-                 gp_Pnt2d&        PntSol) const{
-   if (!WellDone) { StdFail_NotDone::Raise(); }
-   else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
-   else {
-     if (TheSame1(Index) == 0) {
-       ParSol = par1sol(Index);
-       ParArg = pararg1(Index);
-       PntSol = gp_Pnt2d(pnttg1sol(Index));
-     }
-     else { StdFail_NotDone::Raise(); }
-   }
- }
+Tangency1 (const Standard_Integer Index,
+           Standard_Real&   ParSol,
+           Standard_Real&   ParArg,
+           gp_Pnt2d&        PntSol) const{
+             if (!WellDone) { StdFail_NotDone::Raise(); }
+             else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
+             else {
+               if (TheSame1(Index) == 0) {
+                 ParSol = par1sol(Index);
+                 ParArg = pararg1(Index);
+                 PntSol = gp_Pnt2d(pnttg1sol(Index));
+               }
+               else { StdFail_NotDone::Raise(); }
+             }
+}
 
 void GccGeo_Circ2d2TanRad::
 
 void GccGeo_Circ2d2TanRad::
-   Tangency2 (const Standard_Integer Index,
-                 Standard_Real&   ParSol,
-                 Standard_Real&   ParArg,
-                 gp_Pnt2d&        PntSol) const{
-   if (!WellDone) { StdFail_NotDone::Raise(); }
-   else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
-   else {
-     if (TheSame2(Index) == 0) {
-       ParSol = par2sol(Index);
-       ParArg = pararg2(Index);
-       PntSol = gp_Pnt2d(pnttg2sol(Index));
-     }
-     else { StdFail_NotDone::Raise(); }
-   }
- }
+Tangency2 (const Standard_Integer Index,
+           Standard_Real&   ParSol,
+           Standard_Real&   ParArg,
+           gp_Pnt2d&        PntSol) const{
+             if (!WellDone) { StdFail_NotDone::Raise(); }
+             else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
+             else {
+               if (TheSame2(Index) == 0) {
+                 ParSol = par2sol(Index);
+                 ParArg = pararg2(Index);
+                 PntSol = gp_Pnt2d(pnttg2sol(Index));
+               }
+               else { StdFail_NotDone::Raise(); }
+             }
+}
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
-   IsTheSame1 (const Standard_Integer Index) const
+IsTheSame1 (const Standard_Integer Index) const
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
@@ -786,7 +1011,7 @@ Standard_Boolean GccGeo_Circ2d2TanRad::
 }
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
 }
 
 Standard_Boolean GccGeo_Circ2d2TanRad::
-   IsTheSame2 (const Standard_Integer Index) const
+IsTheSame2 (const Standard_Integer Index) const
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
 {
   if (!WellDone) { StdFail_NotDone::Raise(); }
   if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
index ce662f0..d07303f 100755 (executable)
@@ -148,12 +148,85 @@ static Standard_Integer OCC137_z (Draw_Interpretor& di, Standard_Integer argc, c
   return 0;
 }
 
   return 0;
 }
 
+#include <GccEnt_Position.hxx>
+#include <Geom2dGcc_QualifiedCurve.hxx>
+#include <Geom2dGcc_Circ2d2TanRad.hxx>
+#include <gp_Elips2d.hxx>
+#include <Geom2d_Ellipse.hxx>
+#include <Geom2d_Circle.hxx>
+
+static Standard_Integer OCC24303(Draw_Interpretor& di, Standard_Integer n, const char** a)
+{
+  if(n < 2)
+    return 1;
+
+  const Standard_Integer SolID = Draw::Atoi(a[1]);
+
+  //Ellipses
+  Standard_Real majorRadius = 2.0;
+  Standard_Real minorRadius = 1.0;
+  gp_Pnt2d p0(gp::Origin2d());
+  gp_Pnt2d p1(4.0,0.0);
+
+  gp_Elips2d ellipse1 = gp_Elips2d( gp_Ax2d(p0,gp::DX2d()),majorRadius, minorRadius,true);
+  gp_Elips2d ellipse2 = gp_Elips2d( gp_Ax2d(p1,gp::DX2d()),majorRadius, minorRadius,true);
+
+  Handle_Geom2d_Curve curve1 = new Geom2d_Ellipse(ellipse1);
+  Handle_Geom2d_Curve curve2 = new Geom2d_Ellipse(ellipse2);
+  DrawTrSurf::Set("c1", curve1);
+  DrawTrSurf::Set("c2", curve2);
+  //Expected tangent
+  gp_Pnt2d centre(5.0,0.0);
+  Standard_Real radius = 3.0;
+  gp_Circ2d theorical_tangent = gp_Circ2d(gp_Ax2d(centre,gp::DX2d()),radius);
+
+  //Calculate the tangent with Geom2dGcc_Circ2dTanRan
+
+  const Geom2dAdaptor_Curve  AdaptedCurve1 ( curve1 );
+  const Geom2dAdaptor_Curve  AdaptedCurve2 ( curve2 );
+
+  GccEnt_Position  curveQualif1 = GccEnt_unqualified;
+  GccEnt_Position  curveQualif2 = GccEnt_unqualified;
+
+  const Geom2dGcc_QualifiedCurve qualifiedCurve1 ( AdaptedCurve1, curveQualif1 );
+  const Geom2dGcc_QualifiedCurve qualifiedCurve2 ( AdaptedCurve2, curveQualif2 );
+
+  const Geom2dGcc_Circ2d2TanRad circCalc(qualifiedCurve1,qualifiedCurve2,radius,/*Precision::Approximation()*/ 1.0e-9);
+
+  const Standard_Integer aNbSol = circCalc.NbSolutions();
+  di << "Solutions " << aNbSol << "\n";
+
+  if((SolID < 1) || (SolID > aNbSol))
+  {
+    di << "Wrong SolID value\n";
+    return 1;
+  }
+
+  gp_Circ2d calculated_tangent = circCalc.ThisSolution(SolID);
+
+  char Buf[10];
+  for (Standard_Integer i = 1; i <= aNbSol; i++)
+  {
+    gp_Circ2d ct = circCalc.ThisSolution(i);
+    Handle (Geom2d_Circle) GSol = new Geom2d_Circle(ct);
+    Sprintf(Buf, "Sol%d",i);
+    DrawTrSurf::Set(Buf, GSol);
+  }
+
+  //This distance is different in OC 6.5.4 and OC 6.6.0
+  Standard_Real dist = theorical_tangent.Location().Distance(calculated_tangent.Location());
+  di << "Distance = " << dist << "\n";
+
+  return 0;
+}
+
 void QABugs::Commands_9(Draw_Interpretor& theCommands) {
   const char *group = "QABugs";
 
   theCommands.Add ("BUC60857", "BUC60857", __FILE__, BUC60857, group);
   theCommands.Add("OCC137","OCC137 mode [shape]",__FILE__,OCC137,group);
   theCommands.Add("OCC137_z","OCC137_z [ZDetection_mode]",__FILE__,OCC137_z,group);
 void QABugs::Commands_9(Draw_Interpretor& theCommands) {
   const char *group = "QABugs";
 
   theCommands.Add ("BUC60857", "BUC60857", __FILE__, BUC60857, group);
   theCommands.Add("OCC137","OCC137 mode [shape]",__FILE__,OCC137,group);
   theCommands.Add("OCC137_z","OCC137_z [ZDetection_mode]",__FILE__,OCC137_z,group);
+  theCommands.Add("OCC24303", "OCC24303 SolID ",       __FILE__,       OCC24303,group);
 
   return;
 }
 
   return;
 }
diff --git a/tests/bugs/modalg_5/bug24303 b/tests/bugs/modalg_5/bug24303
new file mode 100755 (executable)
index 0000000..14a8ea6
--- /dev/null
@@ -0,0 +1,67 @@
+puts "============"
+puts "OCC24303"
+puts "============"
+puts ""
+###############################
+## Precision degradation for Geom2dGcc_Circ2d2TanRad in OCCT6.6.0.
+###############################
+
+pload QAcommands
+
+set status 0
+
+set info1 [OCC24303 4]
+regexp {Solutions +([-0-9.+eE]+)} ${info1} full Solution
+regexp {Distance += +([-0-9.+eE]+)} ${info1} full Distance
+
+if { [info exists Sol4] } {
+   set info2 [dump Sol4]
+   regexp {Center +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full CenterX CenterY
+   regexp {XAxis +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full XAxisX XAxisY
+   regexp {YAxis +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full YAxisX YAxisY
+   regexp {Radius +:([-0-9.+eE]+)} ${info2} full Radius
+   set good_CenterX 5
+   set good_CenterY 0
+   set good_XAxisX 1
+   set good_XAxisY 0
+   set good_YAxisX 0
+   set good_YAxisY 1
+   set good_Radius 3
+   if { ${CenterX} != ${good_CenterX} } {
+      puts "Faulty : Bad CenterX"
+      set status 1
+   }
+   if { ${CenterY} != ${good_CenterY} } {
+      puts "Faulty : Bad CenterY"
+      set status 1
+   }
+   if { ${XAxisX} != ${good_XAxisX} } {
+      puts "Faulty : Bad XAxisX"
+      set status 1
+   }
+   if { ${XAxisY} != ${good_XAxisY} } {
+      puts "Faulty : Bad XAxisY"
+      set status 1
+   }
+   if { ${YAxisX} != ${good_YAxisX} } {
+      puts "Faulty : Bad YAxisX"
+      set status 1
+   }
+   if { ${YAxisY} != ${good_YAxisY} } {
+      puts "Faulty : Bad YAxisY"
+       set status 1
+  }
+   if { ${Radius} != ${good_Radius} } {
+      puts "Faulty : Bad Radius"
+      set status 1
+   }
+   } else {
+   puts "Faulty : Bad solution"
+   set status 1
+}
+
+if { ${status} != 0 } {
+    puts "Faulty : solution is wrong"
+} else {
+    puts "OK : solution is correct"
+}