0031303: Different calculation of offset direction in Adaptor2d_OffsetCurve and Geom2...
[occt.git] / src / Geom2dGcc / Geom2dGcc_Circ2d2TanRadGeo.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 <Adaptor2d_OffsetCurve.hxx>
17 #include <ElCLib.hxx>
18 #include <GccEnt_BadQualifier.hxx>
19 #include <GccEnt_QualifiedCirc.hxx>
20 #include <GccEnt_QualifiedLin.hxx>
21 #include <Geom2dAdaptor_HCurve.hxx>
22 #include <Geom2dGcc_Circ2d2TanRadGeo.hxx>
23 #include <Geom2dGcc_CurveTool.hxx>
24 #include <Geom2dGcc_QCurve.hxx>
25 #include <Geom2dInt_GInter.hxx>
26 #include <gp_Ax2d.hxx>
27 #include <gp_Circ2d.hxx>
28 #include <gp_Lin2d.hxx>
29 #include <gp_Pnt2d.hxx>
30 #include <IntRes2d_Domain.hxx>
31 #include <IntRes2d_IntersectionPoint.hxx>
32 #include <Standard_NegativeValue.hxx>
33 #include <Standard_OutOfRange.hxx>
34 #include <StdFail_NotDone.hxx>
35 #include <TColStd_Array1OfReal.hxx>
36
37 static const Standard_Integer aNbSolMAX = 16;
38
39 // circulaire tant a une courbe et une droite ,de rayon donne
40 //==============================================================
41
42 //========================================================================
43 // On initialise WellDone a false.                                       +
44 // On recupere la courbe Cu2 et la droite L1.                            +
45 // On sort en erreur dans les cas ou la construction est impossible.     +
46 // On fait la parallele a Cu2 dans le bon sens.                          +
47 // On fait la parallele a L1 dans le bon sens.                           +
48 // On intersecte les paralleles ==> point de centre de la solution.      +
49 // On cree la solution qu on ajoute aux solutions deja trouvees.         +
50 // On remplit les champs.                                                +
51 //========================================================================
52
53 Geom2dGcc_Circ2d2TanRadGeo::
54 Geom2dGcc_Circ2d2TanRadGeo (const GccEnt_QualifiedLin&  Qualified1,
55                             const Geom2dGcc_QCurve&     Qualified2,
56                             const Standard_Real         Radius    ,
57                             const Standard_Real         Tolerance ):
58
59 //========================================================================
60 // initialisation des champs.                                            +
61 //========================================================================
62
63 cirsol(1,aNbSolMAX)   ,
64 qualifier1(1,aNbSolMAX),
65 qualifier2(1,aNbSolMAX),
66 TheSame1(1,aNbSolMAX) ,
67 TheSame2(1,aNbSolMAX) ,
68 pnttg1sol(1,aNbSolMAX),
69 pnttg2sol(1,aNbSolMAX),
70 par1sol(1,aNbSolMAX)  ,
71 par2sol(1,aNbSolMAX)  ,
72 pararg1(1,aNbSolMAX)  ,
73 pararg2(1,aNbSolMAX)  
74 {
75
76   //========================================================================
77   // Traitement.                                                           +
78   //========================================================================
79
80   Standard_Real Tol = Abs(Tolerance);
81   Standard_Real thefirst = -100000.;
82   Standard_Real thelast  =  100000.;
83   Standard_Real firstparam;
84   Standard_Real lastparam;
85   gp_Dir2d dirx(1.,0.);
86   TColStd_Array1OfReal cote1(1,2);
87   TColStd_Array1OfReal cote2(1,2);
88   Standard_Integer nbrcote1=0;
89   Standard_Integer nbrcote2=0;
90   WellDone = Standard_False;
91   NbrSol = 0;
92   if (!(Qualified1.IsEnclosed() ||
93     Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
94     !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
95     Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
96
97       throw GccEnt_BadQualifier();
98       return;
99   }
100   gp_Lin2d L1 = Qualified1.Qualified();
101   Standard_Real x1dir = (L1.Direction()).X();
102   Standard_Real y1dir = (L1.Direction()).Y();
103   Standard_Real lxloc = (L1.Location()).X();
104   Standard_Real lyloc = (L1.Location()).Y();
105   gp_Pnt2d origin1(lxloc,lyloc);
106   gp_Dir2d normL1(-y1dir,x1dir);
107   Geom2dAdaptor_Curve Cu2= Qualified2.Qualified();
108   if (Radius < 0.0) { throw Standard_NegativeValue(); }
109   else {
110     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
111       //   =======================================================
112       nbrcote1 = 1;
113       nbrcote2 = 1;
114       cote1(1) = Radius;
115       cote2(1) = Radius;
116     }
117     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
118       //   ==========================================================
119       nbrcote1 = 1;
120       nbrcote2 = 1;
121       cote1(1) = Radius;
122       cote2(1) = -Radius;
123     }
124     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
125       //   ===========================================================
126       nbrcote1 = 1;
127       nbrcote2 = 1;
128       cote1(1) = -Radius;
129       cote2(1) = Radius;
130     }
131     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
132       //   =========================================================
133       nbrcote1 = 1;
134       nbrcote2 = 1;
135       cote1(1) = -Radius;
136       cote2(1) = -Radius;
137     }
138     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
139       //   =========================================================
140       nbrcote1 = 1;
141       nbrcote2 = 2;
142       cote1(1) = Radius;
143       cote2(1) = Radius;
144       cote2(2) = -Radius;
145     }
146     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
147       //   =========================================================
148       nbrcote1 = 2;
149       nbrcote2 = 1;
150       cote1(1) = Radius;
151       cote1(2) = -Radius;
152       cote2(1) = Radius;
153     }
154     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
155       //   =============================================================
156       nbrcote1 = 1;
157       nbrcote2 = 2;
158       cote1(1) = -Radius;
159       cote2(1) = Radius;
160       cote2(2) = -Radius;
161     }
162     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
163       //   ========================================================
164       nbrcote1 = 2;
165       nbrcote2 = 1;
166       cote1(1) = Radius;
167       cote1(2) = -Radius;
168       cote2(1) = -Radius;
169     }
170     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
171       //   =================================================================
172       nbrcote1 = 2;
173       nbrcote2 = 2;
174       cote1(1) = Radius;
175       cote1(2) = -Radius;
176       cote2(1) = Radius;
177       cote2(2) = -Radius;
178     }
179     gp_Dir2d Dir(-y1dir,x1dir);
180     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
181       gp_Pnt2d Point(L1.Location().XY()+cote1(jcote1)*Dir.XY());
182       gp_Lin2d Line(Point,L1.Direction()); // ligne avec deport.
183       IntRes2d_Domain D1;
184       for (Standard_Integer jcote2 = 1; jcote2 <= nbrcote2 && NbrSol < aNbSolMAX; jcote2++) {
185         Handle(Geom2dAdaptor_HCurve) HCu2 = new Geom2dAdaptor_HCurve(Cu2);
186         //Adaptor2d_OffsetCurve C2(HCu2,cote2(jcote2));
187         Adaptor2d_OffsetCurve C2(HCu2, -cote2(jcote2));
188         firstparam = Max(C2.FirstParameter(),thefirst);
189         lastparam  = Min(C2.LastParameter(),thelast);
190         IntRes2d_Domain D2(C2.Value(firstparam), firstparam, Tol,
191                            C2.Value(lastparam), lastparam, Tol);
192         Geom2dInt_TheIntConicCurveOfGInter Intp(Line,D1,C2,D2,Tol,Tol);
193         if (Intp.IsDone()) {
194           if (!Intp.IsEmpty()) {
195             for (Standard_Integer i = 1; i <= Intp.NbPoints() && NbrSol < aNbSolMAX; i++) {
196               NbrSol++;
197               gp_Pnt2d Center(Intp.Point(i).Value());
198               cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
199               //             =======================================================
200               gp_Dir2d dc1(origin1.XY()-Center.XY());
201               qualifier2(NbrSol) = Qualified2.Qualifier();
202               if (!Qualified1.IsUnqualified()) { 
203                 qualifier1(NbrSol) = Qualified1.Qualifier();
204               }
205               else if (dc1.Dot(normL1) > 0.0) {
206                 qualifier1(NbrSol) = GccEnt_outside;
207               }
208               else { qualifier1(NbrSol) = GccEnt_enclosed; }
209               TheSame1(NbrSol) = 0;
210               TheSame2(NbrSol) = 0;
211               pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
212               pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
213               pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),L1);
214               pnttg2sol(NbrSol) = Geom2dGcc_CurveTool::Value(Cu2,pararg2(NbrSol));
215               par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
216                 pnttg1sol(NbrSol));
217               par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
218                 pnttg2sol(NbrSol));
219             }
220           }
221           WellDone = Standard_True;
222         }
223       }
224     }
225   }
226 }
227
228 // circulaire tant a une courbe et un cercle ,de rayon donne
229 //=============================================================
230
231 //========================================================================
232 // On initialise WellDone a false.                                       +
233 // On recupere la courbe Cu2 et le cercle C1.                            +
234 // On sort en erreur dans les cas ou la construction est impossible.     +
235 // On fait la parallele a Cu2 dans le bon sens.                          +
236 // On fait la parallele a C1 dans le bon sens.                           +
237 // On intersecte les paralleles ==> point de centre de la solution.      +
238 // On cree la solution qu on ajoute aux solutions deja trouvees.         +
239 // On remplit les champs.                                                +
240 //========================================================================
241
242 Geom2dGcc_Circ2d2TanRadGeo::
243 Geom2dGcc_Circ2d2TanRadGeo (const GccEnt_QualifiedCirc& Qualified1,
244                             const Geom2dGcc_QCurve&     Qualified2,
245                             const Standard_Real         Radius    ,
246                             const Standard_Real         Tolerance ):
247
248 //========================================================================
249 // initialisation des champs.                                            +
250 //========================================================================
251
252 cirsol(1,aNbSolMAX)   ,
253 qualifier1(1,aNbSolMAX),
254 qualifier2(1,aNbSolMAX),
255 TheSame1(1,aNbSolMAX) ,
256 TheSame2(1,aNbSolMAX) ,
257 pnttg1sol(1,aNbSolMAX),
258 pnttg2sol(1,aNbSolMAX),
259 par1sol(1,aNbSolMAX)  ,
260 par2sol(1,aNbSolMAX)  ,
261 pararg1(1,aNbSolMAX)  ,
262 pararg2(1,aNbSolMAX)  
263 {
264
265   //========================================================================
266   // Traitement.                                                           +
267   //========================================================================
268
269   Standard_Real Tol = Abs(Tolerance);
270   Standard_Real thefirst = -100000.;
271   Standard_Real thelast  =  100000.;
272   Standard_Real firstparam;
273   Standard_Real lastparam;
274   gp_Dir2d dirx(1.,0.);
275   TColStd_Array1OfReal cote1(1,2);
276   TColStd_Array1OfReal cote2(1,2);
277   Standard_Integer nbrcote1=0;
278   Standard_Integer nbrcote2=0;
279   WellDone = Standard_False;
280   NbrSol = 0;
281   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
282     Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
283     !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
284     Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
285       throw GccEnt_BadQualifier();
286       return;
287   }
288   gp_Circ2d C1 = Qualified1.Qualified();
289   gp_Pnt2d center1(C1.Location());
290   Geom2dAdaptor_Curve Cu2 = Qualified2.Qualified();
291   if (Radius < 0.0) { throw Standard_NegativeValue(); }
292   else {
293     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
294       //   =======================================================
295       nbrcote1 = 1;
296       nbrcote2 = 1;
297       cote1(1) = Radius;
298       cote2(1) = Radius;
299     }
300     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
301       //   ==========================================================
302       nbrcote1 = 1;
303       nbrcote2 = 1;
304       cote1(1) = Radius;
305       cote2(1) = -Radius;
306     }
307     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
308       //   ===========================================================
309       nbrcote1 = 1;
310       nbrcote2 = 1;
311       cote1(1) = -Radius;
312       cote2(1) = Radius;
313     }
314     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
315       //   =========================================================
316       nbrcote1 = 1;
317       nbrcote2 = 1;
318       cote1(1) = -Radius;
319       cote2(1) = -Radius;
320     }
321     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
322       //   =========================================================
323       nbrcote1 = 1;
324       nbrcote2 = 2;
325       cote1(1) = Radius;
326       cote2(1) = Radius;
327       cote2(2) = -Radius;
328     }
329     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
330       //   =========================================================
331       nbrcote1 = 2;
332       nbrcote2 = 1;
333       cote1(1) = Radius;
334       cote1(2) = -Radius;
335       cote2(1) = Radius;
336     }
337     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
338       //   =============================================================
339       nbrcote1 = 1;
340       nbrcote2 = 2;
341       cote1(1) = -Radius;
342       cote2(1) = Radius;
343       cote2(2) = -Radius;
344     }
345     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
346       //   ========================================================
347       nbrcote1 = 2;
348       nbrcote2 = 1;
349       cote1(1) = Radius;
350       cote1(2) = -Radius;
351       cote2(1) = -Radius;
352     }
353     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
354       //   =================================================================
355       nbrcote1 = 2;
356       nbrcote2 = 2;
357       cote1(1) = Radius;
358       cote1(2) = -Radius;
359       cote2(1) = Radius;
360       cote2(2) = -Radius;
361     }
362     Standard_Real R1 = C1.Radius();
363     Geom2dInt_TheIntConicCurveOfGInter Intp;
364     for (Standard_Integer jcote1 = 1; jcote1 <= nbrcote1 && NbrSol < aNbSolMAX; jcote1++) {
365       gp_Circ2d Circ(C1.XAxis(),R1+cote1(jcote1));
366       IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
367         ElCLib::Value(2.*M_PI,Circ),2.*M_PI,Tol);
368       D1.SetEquivalentParameters(0.,2.*M_PI);
369       for (Standard_Integer jcote2 = 1 ; jcote2 <= nbrcote2 ; jcote2++) {
370         Handle(Geom2dAdaptor_HCurve) HCu2 = new Geom2dAdaptor_HCurve(Cu2);
371         //Adaptor2d_OffsetCurve C2(HCu2,cote2(jcote2));
372         Adaptor2d_OffsetCurve C2(HCu2, -cote2(jcote2));
373         firstparam = Max(C2.FirstParameter(),thefirst);
374         lastparam  = Min(C2.LastParameter(),thelast);
375         IntRes2d_Domain D2(C2.Value(firstparam), firstparam, Tol,
376                            C2.Value(lastparam), lastparam, Tol);
377         Intp.Perform(Circ,D1,C2,D2,Tol,Tol);
378         if (Intp.IsDone()) {
379           if (!Intp.IsEmpty()) {
380             for (Standard_Integer i = 1; i <= Intp.NbPoints() && NbrSol < aNbSolMAX; i++) {
381               NbrSol++;
382               gp_Pnt2d Center(Intp.Point(i).Value());
383               cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
384               //             =======================================================
385 #ifdef OCCT_DEBUG
386               gp_Dir2d dir1(Center.XY()-center1.XY());
387 #else
388               Center.XY() ;
389               center1.XY() ;
390 #endif
391               Standard_Real distcc1 = Center.Distance(center1);
392               if (!Qualified1.IsUnqualified()) { 
393                 qualifier1(NbrSol) = Qualified1.Qualifier();
394               }
395               else if (Abs(distcc1+Radius-R1) < Tol) {
396                 qualifier1(NbrSol) = GccEnt_enclosed;
397               }
398               else if (Abs(distcc1-R1-Radius) < Tol) {
399                 qualifier1(NbrSol) = GccEnt_outside;
400               }
401               else { qualifier1(NbrSol) = GccEnt_enclosing; }
402               qualifier2(NbrSol) = Qualified2.Qualifier();
403               TheSame1(NbrSol) = 0;
404               TheSame2(NbrSol) = 0;
405               pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
406               pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
407               pnttg1sol(NbrSol) = ElCLib::Value(pararg1(NbrSol),C1);
408               pnttg2sol(NbrSol) = Geom2dGcc_CurveTool::Value(Cu2,pararg2(NbrSol));
409               par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
410                 pnttg1sol(NbrSol));
411               par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
412                 pnttg2sol(NbrSol));
413             }
414           }
415           WellDone = Standard_True;
416         }
417       }
418     }
419   }
420 }
421
422 // circulaire tant a une courbe et un point ,de rayon donne
423 //============================================================
424
425 //========================================================================
426 // On initialise WellDone a false.                                       +
427 // On recupere la courbe Cu1 et le point P2.                             +
428 // On sort en erreur dans les cas ou la construction est impossible.     +
429 // On fait la parallele a Cu1 dans le bon sens.                          +
430 // On fait la parallele a P2 dans le bon sens.                           +
431 // On intersecte les paralleles ==> point de centre de la solution.      +
432 // On cree la solution qu on ajoute aux solutions deja trouvees.         +
433 // On remplit les champs.                                                +
434 //========================================================================
435
436 Geom2dGcc_Circ2d2TanRadGeo::
437 Geom2dGcc_Circ2d2TanRadGeo (const Geom2dGcc_QCurve& Qualified1,
438                             const gp_Pnt2d&     Point2    ,
439                             const Standard_Real Radius    ,
440                             const Standard_Real Tolerance ):
441
442 //========================================================================
443 // initialisation des champs.                                            +
444 //========================================================================
445
446 cirsol(1,aNbSolMAX)   ,
447 qualifier1(1,aNbSolMAX),
448 qualifier2(1,aNbSolMAX),
449 TheSame1(1,aNbSolMAX) ,
450 TheSame2(1,aNbSolMAX) ,
451 pnttg1sol(1,aNbSolMAX),
452 pnttg2sol(1,aNbSolMAX),
453 par1sol(1,aNbSolMAX)  ,
454 par2sol(1,aNbSolMAX)  ,
455 pararg1(1,aNbSolMAX)  ,
456 pararg2(1,aNbSolMAX)  
457 {
458
459   //========================================================================
460   // Traitement.                                                           +
461   //========================================================================
462
463   Standard_Real Tol = Abs(Tolerance);
464   Standard_Real thefirst = -100000.;
465   Standard_Real thelast  =  100000.;
466   Standard_Real firstparam;
467   Standard_Real lastparam;
468   gp_Dir2d dirx(1.,0.);
469   TColStd_Array1OfReal cote1(1,2);
470   Standard_Integer nbrcote1=0;
471   WellDone = Standard_False;
472   NbrSol = 0;
473   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
474     Qualified1.IsOutside() || Qualified1.IsUnqualified())) {
475       throw GccEnt_BadQualifier();
476       return;
477   }
478   Geom2dAdaptor_Curve Cu1 = Qualified1.Qualified();
479   if (Radius < 0.0) { throw Standard_NegativeValue(); }
480   else {
481     if (Qualified1.IsEnclosed()) {
482       //    ===========================
483       nbrcote1 = 1;
484       cote1(1) = Radius;
485     }
486     else if(Qualified1.IsOutside()) {
487       //   ===============================
488       nbrcote1 = 1;
489       cote1(1) = -Radius;
490     }
491     else if(Qualified1.IsUnqualified()) {
492       //   ===================================
493       nbrcote1 = 2;
494       cote1(1) = Radius;
495       cote1(2) = -Radius;
496     }
497     gp_Circ2d Circ(gp_Ax2d(Point2,gp_Dir2d(1.,0.)),Radius);
498     IntRes2d_Domain D1(ElCLib::Value(0.,Circ),   0.,Tol,
499       ElCLib::Value(M_PI+M_PI,Circ),M_PI+M_PI,Tol);
500     D1.SetEquivalentParameters(0.,M_PI+M_PI);
501     Geom2dInt_TheIntConicCurveOfGInter Intp;
502     for (Standard_Integer jcote1 = 1; jcote1 <= nbrcote1 && NbrSol < aNbSolMAX; jcote1++) {
503       Handle(Geom2dAdaptor_HCurve) HCu1 = new Geom2dAdaptor_HCurve(Cu1);
504       //Adaptor2d_OffsetCurve Cu2(HCu1,cote1(jcote1));
505       Adaptor2d_OffsetCurve Cu2(HCu1,-cote1(jcote1));
506       firstparam = Max(Cu2.FirstParameter(),thefirst);
507       lastparam  = Min(Cu2.LastParameter(),thelast);
508       IntRes2d_Domain D2(Cu2.Value(firstparam), firstparam, Tol,
509                          Cu2.Value(lastparam), lastparam, Tol);
510       Intp.Perform(Circ,D1,Cu2,D2,Tol,Tol);
511       if (Intp.IsDone()) {
512         if (!Intp.IsEmpty()) {
513           for (Standard_Integer i = 1; i <= Intp.NbPoints() && NbrSol < aNbSolMAX; i++) {
514             NbrSol++;
515             gp_Pnt2d Center(Intp.Point(i).Value());
516             cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
517             //           =======================================================
518             qualifier1(NbrSol) = Qualified1.Qualifier();
519             qualifier2(NbrSol) = GccEnt_noqualifier;
520             TheSame1(NbrSol) = 0;
521             TheSame2(NbrSol) = 0;
522             pararg1(NbrSol) = Intp.Point(i).ParamOnSecond();
523             pararg2(NbrSol) = 0.;
524             pnttg1sol(NbrSol) = Geom2dGcc_CurveTool::Value(Cu1,pararg1(NbrSol));
525             pnttg2sol(NbrSol) = Point2;
526             par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
527               pnttg1sol(NbrSol));
528             par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
529               pnttg2sol(NbrSol));
530           }
531         }
532         WellDone = Standard_True;
533       }
534     }
535   }
536 }
537
538 //=======================================================================
539 //function : PrecRoot
540 //purpose  : In case, when curves has tangent zones, intersection point
541 //            found may be precised. This function uses precision algorithm
542 //            of Extrema Curve-Curve method (dot product between every
543 //            tangent vector and vector between points in two curves must
544 //            be equal to zero).
545 //=======================================================================
546 static void PrecRoot(const Adaptor2d_OffsetCurve& theC1,
547                      const Adaptor2d_OffsetCurve& theC2,
548                      const Standard_Real theU0,
549                      const Standard_Real theV0,
550                      Standard_Real& theUfinal,
551                      Standard_Real& theVfinal)
552 {
553 /*
554 It is necessary for precision to solve the system
555
556     \left\{\begin{matrix}
557     (x_{1}(u)-x_{2}(v))*{x_{1}(u)}'+(y_{1}(u)-y_{2}(v))*{y_{1}(u)}'=0\\ 
558     (x_{1}(u)-x_{2}(v))*{x_{2}(v)}'+(y_{1}(u)-y_{2}(v))*{y_{2}(v)}'=0
559     \end{matrix}\right.
560
561 Precision of any 2*2-system (two equation and two variables)
562
563     \left\{\begin{matrix}
564     S_{1}(u,v)=0\\ 
565     S_{2}(u,v)=0
566     \end{matrix}\right.
567
568 by Newton method can be made as follows:
569
570     u=u_{0}-\left (\frac{\frac{\partial S_{2}}{\partial v}*S_{1}-
571       \frac{\partial S_{1}}{\partial v}*S_{2}}
572       {\frac{\partial S_{1}}{\partial u}*
573       \frac{\partial S_{2}}{\partial v}-
574       \frac{\partial S_{1}}{\partial v}*
575       \frac{\partial S_{2}}{\partial u}}  \right )_{u_{0},v_{0}}\\ 
576     v=v_{0}-\left (\frac{\frac{\partial S_{1}}{\partial u}*S_{2}-
577       \frac{\partial S_{2}}{\partial u}*S_{1}}
578       {\frac{\partial S_{1}}{\partial u}*
579       \frac{\partial S_{2}}{\partial v}-
580       \frac{\partial S_{1}}{\partial v}*
581       \frac{\partial S_{2}}{\partial u}}  \right )_{u_{0},v_{0}}
582     \end{matrix}\right.
583
584 where u_{0} and v_{0} are initial values or values computed on previous iteration.
585 */
586
587   theUfinal = theU0;
588   theVfinal = theV0;
589
590   const Standard_Integer aNbIterMax = 100;
591
592   Standard_Real aU = theU0, aV = theV0;
593   gp_Pnt2d aPu, aPv;
594   gp_Vec2d aD1u, aD1v, aD2u, aD2v;
595
596   Standard_Integer aNbIter = 0;
597
598   Standard_Real aStepU = 0.0, aStepV = 0.0;
599
600   Standard_Real aSQDistPrev = RealFirst();
601
602   theC1.D2(aU, aPu, aD1u, aD2u);
603   theC2.D2(aV, aPv, aD1v, aD2v);
604
605   const Standard_Real aCrProd = Abs(aD1u.Crossed(aD1v));
606   if(aCrProd*aCrProd > 1.0e-6*
607       aD1u.SquareMagnitude()*aD1v.SquareMagnitude())
608   {
609     //Curves are not tangent. Therefore, we consider that 
610     //2D-intersection algorithm have found good point which
611     //did not need in more precision.
612     return;
613   }
614
615   do
616   {
617     aNbIter++;
618
619     gp_Vec2d aVuv(aPv, aPu);
620
621     Standard_Real aSQDist = aVuv.SquareMagnitude();
622     if(IsEqual(aSQDist, 0.0))
623       break;
624
625     if((aNbIter == 1) || (aSQDist < aSQDistPrev))
626     {
627       aSQDistPrev = aSQDist;
628       theUfinal = aU;
629       theVfinal = aV;
630     }
631
632
633     Standard_Real aG1 = aD1u.Magnitude();
634     Standard_Real aG2 = aD1v.Magnitude();
635
636     if(IsEqual(aG1, 0.0) || IsEqual(aG2, 0.0))
637     {//Here we do not processing singular cases.
638       break;
639     }
640
641     Standard_Real aF1 = aVuv.Dot(aD1u);
642     Standard_Real aF2 = aVuv.Dot(aD1v);
643
644     Standard_Real aFIu = aVuv.Dot(aD2u);
645     Standard_Real aFIv = aVuv.Dot(aD2v);
646     Standard_Real aPSIu = aD1u.Dot(aD2u);
647     Standard_Real aPSIv = aD1v.Dot(aD2v);
648
649     Standard_Real aTheta = aD1u*aD1v;
650
651     Standard_Real aS1 = aF1/aG1;
652     Standard_Real aS2 = aF2/aG2;
653
654     Standard_Real aDS1u = (aG1*aG1+aFIu)/aG1 - (aS1*aPSIu/(aG1*aG1));
655     Standard_Real aDS1v = -aTheta/aG1;
656     Standard_Real aDS2u = aTheta/aG2;
657     Standard_Real aDS2v = (aFIv-aG2*aG2)/aG2 - (aS2*aPSIv/(aG2*aG2));
658
659     Standard_Real aDet = aDS1u*aDS2v-aDS1v*aDS2u;
660
661     if(IsEqual(aDet, 0.0))
662     {
663       if(!IsEqual(aStepV, 0.0) && !IsEqual(aDS1u, 0.0))
664       {
665         aV += aStepV;
666         aU = aU - (aDS1v*aStepV - aS1)/aDS1u;
667       }
668       else if(!IsEqual(aStepU, 0.0) && !IsEqual(aDS1v, 0.0))
669       {
670         aU += aStepU;
671         aV = aV - (aDS1u*aStepU - aS1)/aDS1v;
672       }
673       else
674       {
675         break;
676       }
677     }
678     else
679     {
680       aStepU = -(aS1*aDS2v-aS2*aDS1v)/aDet;
681       aStepV = -(aS2*aDS1u-aS1*aDS2u)/aDet;
682
683       if(Abs(aStepU) < Epsilon(Abs(aU)))
684       {
685         if(Abs(aStepV) < Epsilon(Abs(aV)))
686         {
687           break;
688         }
689       }
690
691       aU += aStepU;
692       aV += aStepV;
693     }
694
695     theC1.D2(aU, aPu, aD1u, aD2u);
696     theC2.D2(aV, aPv, aD1v, aD2v);
697   }
698   while(aNbIter <= aNbIterMax);
699 }
700
701
702
703 // circulaire tant a deux courbes ,de rayon donne
704 //==================================================
705
706 //========================================================================
707 // On initialise WellDone a false.                                       +
708 // On recupere les courbes Cu1 et Cu2.                                   +
709 // On sort en erreur dans les cas ou la construction est impossible.     +
710 // On fait la parallele a Cu1 dans le bon sens.                          +
711 // On fait la parallele a Cu2 dans le bon sens.                          +
712 // On intersecte les paralleles ==> point de centre de la solution.      +
713 // On cree la solution qu on ajoute aux solutions deja trouvees.         +
714 // On remplit les champs.                                                +
715 //========================================================================
716 Geom2dGcc_Circ2d2TanRadGeo::
717 Geom2dGcc_Circ2d2TanRadGeo (const Geom2dGcc_QCurve& Qualified1,
718                             const Geom2dGcc_QCurve& Qualified2,
719                             const Standard_Real Radius    ,
720                             const Standard_Real Tolerance ):
721
722 //========================================================================
723 // initialisation des champs.                                            +
724 //========================================================================
725
726 cirsol(1,aNbSolMAX)   ,
727 qualifier1(1,aNbSolMAX),
728 qualifier2(1,aNbSolMAX),
729 TheSame1(1,aNbSolMAX) ,
730 TheSame2(1,aNbSolMAX) ,
731 pnttg1sol(1,aNbSolMAX),
732 pnttg2sol(1,aNbSolMAX),
733 par1sol(1,aNbSolMAX)  ,
734 par2sol(1,aNbSolMAX)  ,
735 pararg1(1,aNbSolMAX)  ,
736 pararg2(1,aNbSolMAX)  
737 {
738
739   //========================================================================
740   // Traitement.                                                           +
741   //========================================================================
742
743   Standard_Real Tol = Abs(Tolerance);
744 #ifdef OCCT_DEBUG
745   const Standard_Real thefirst = -100000.;
746   const Standard_Real thelast  =  100000.;
747 #endif
748   gp_Dir2d dirx(1.,0.);
749   TColStd_Array1OfReal cote1(1,2);
750   TColStd_Array1OfReal cote2(1,2);
751   Standard_Integer nbrcote1=0;
752   Standard_Integer nbrcote2=0;
753   WellDone = Standard_False;
754   NbrSol = 0;
755   if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
756     Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
757     !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
758     Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
759       throw GccEnt_BadQualifier();
760       return;
761   }
762   Geom2dAdaptor_Curve Cu1 = Qualified1.Qualified();
763   Geom2dAdaptor_Curve Cu2 = Qualified2.Qualified();
764   if (Radius < 0.0) { throw Standard_NegativeValue(); }
765   else {
766     if (Qualified1.IsEnclosed() && Qualified2.IsEnclosed()) {
767       //   =======================================================
768       nbrcote1 = 1;
769       nbrcote2 = 1;
770       cote1(1) = Radius;
771       cote2(1) = Radius;
772     }
773     else if(Qualified1.IsEnclosed() && Qualified2.IsOutside()) {
774       //   ==========================================================
775       nbrcote1 = 1;
776       nbrcote2 = 1;
777       cote1(1) = Radius;
778       cote2(1) = -Radius;
779     }
780     else if (Qualified1.IsOutside() && Qualified2.IsEnclosed()) {
781       //   ===========================================================
782       nbrcote1 = 1;
783       nbrcote2 = 1;
784       cote1(1) = -Radius;
785       cote2(1) = Radius;
786     }
787     else if(Qualified1.IsOutside() && Qualified2.IsOutside()) {
788       //   =========================================================
789       nbrcote1 = 1;
790       nbrcote2 = 1;
791       cote1(1) = -Radius;
792       cote2(1) = -Radius;
793     }
794     if(Qualified1.IsEnclosed() && Qualified2.IsUnqualified()) {
795       //   =========================================================
796       nbrcote1 = 1;
797       nbrcote2 = 2;
798       cote1(1) = Radius;
799       cote2(1) = Radius;
800       cote2(2) = -Radius;
801     }
802     if(Qualified1.IsUnqualified() && Qualified2.IsEnclosed()) {
803       //   =========================================================
804       nbrcote1 = 2;
805       nbrcote2 = 1;
806       cote1(1) = Radius;
807       cote1(2) = -Radius;
808       cote2(1) = Radius;
809     }
810     else if(Qualified1.IsOutside() && Qualified2.IsUnqualified()) {
811       //   =============================================================
812       nbrcote1 = 1;
813       nbrcote2 = 2;
814       cote1(1) = -Radius;
815       cote2(1) = Radius;
816       cote2(2) = -Radius;
817     }
818     if(Qualified1.IsUnqualified() && Qualified2.IsOutside()) {
819       //   ========================================================
820       nbrcote1 = 2;
821       nbrcote2 = 1;
822       cote1(1) = Radius;
823       cote1(2) = -Radius;
824       cote2(1) = -Radius;
825     }
826     else if(Qualified1.IsUnqualified() && Qualified2.IsUnqualified()) {
827       //   =================================================================
828       nbrcote1 = 2;
829       nbrcote2 = 2;
830       cote1(1) = Radius;
831       cote1(2) = -Radius;
832       cote2(1) = Radius;
833       cote2(2) = -Radius;
834     }
835     Geom2dInt_GInter Intp;
836     for (Standard_Integer jcote1 = 1 ; jcote1 <= nbrcote1 ; jcote1++) {
837       Handle(Geom2dAdaptor_HCurve) HCu1 = new Geom2dAdaptor_HCurve(Cu1); 
838       //Adaptor2d_OffsetCurve C1(HCu1,cote1(jcote1));
839       Adaptor2d_OffsetCurve C1(HCu1, -cote1(jcote1));
840 #ifdef OCCT_DEBUG
841       Standard_Real firstparam = Max(C1.FirstParameter(), thefirst);
842       Standard_Real lastparam = Min(C1.LastParameter(), thelast);
843       IntRes2d_Domain D2C1(C1.Value(firstparam),firstparam,Tol,
844         C1.Value(lastparam),lastparam,Tol);
845 #endif
846       for (Standard_Integer jcote2 = 1; jcote2 <= nbrcote2 && NbrSol < aNbSolMAX; jcote2++) {
847         Handle(Geom2dAdaptor_HCurve) HCu2 = new Geom2dAdaptor_HCurve(Cu2);
848         //Adaptor2d_OffsetCurve C2(HCu2,cote2(jcote2));
849         Adaptor2d_OffsetCurve C2(HCu2, -cote2(jcote2));
850 #ifdef OCCT_DEBUG
851         firstparam = Max(C2.FirstParameter(), thefirst);
852         lastparam  = Min(C2.LastParameter(),thelast);
853         IntRes2d_Domain D2C2(C2.Value(firstparam),firstparam,Tol,
854           C2.Value(lastparam),lastparam,Tol);
855 #endif
856         Intp.Perform(C1,C2,Tol,Tol);
857         if (Intp.IsDone()) {
858           if (!Intp.IsEmpty()) {
859             const Standard_Real aSQApproxTol = Precision::Approximation() *
860                                                 Precision::Approximation();
861             for (Standard_Integer i = 1; i <= Intp.NbPoints() && NbrSol < aNbSolMAX; i++)
862             {
863               Standard_Real aU0 = Intp.Point(i).ParamOnFirst();
864               Standard_Real aV0 = Intp.Point(i).ParamOnSecond();
865
866               Standard_Real aU1 = aU0-Precision::PApproximation();
867               Standard_Real aV1 = aV0-Precision::PApproximation();
868
869               Standard_Real aU2 = aU0+Precision::PApproximation();
870               Standard_Real aV2 = aV0+Precision::PApproximation();
871
872               gp_Pnt2d P11 = C1.Value(aU1);
873               gp_Pnt2d P12 = C2.Value(aV1);
874               gp_Pnt2d P21 = C1.Value(aU2);
875               gp_Pnt2d P22 = C2.Value(aV2);
876
877               Standard_Real aDist1112 = P11.SquareDistance(P12);
878               Standard_Real aDist1122 = P11.SquareDistance(P22);
879
880               Standard_Real aDist1221 = P12.SquareDistance(P21);
881               Standard_Real aDist2122 = P21.SquareDistance(P22);
882
883               if( (Min(aDist1112, aDist1122) <= aSQApproxTol) &&
884                   (Min(aDist1221, aDist2122) <= aSQApproxTol))
885               {
886                 PrecRoot(C1, C2, aU0, aV0, aU0, aV0);
887               }
888
889               NbrSol++;
890               gp_Pnt2d Center(C1.Value(aU0));
891               cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
892               //             =======================================================
893               qualifier1(NbrSol) = Qualified1.Qualifier();
894               qualifier1(NbrSol) = Qualified1.Qualifier();
895               TheSame1(NbrSol) = 0;
896               TheSame2(NbrSol) = 0;
897               pararg1(NbrSol) = Intp.Point(i).ParamOnFirst();
898               pararg2(NbrSol) = Intp.Point(i).ParamOnSecond();
899               pnttg1sol(NbrSol) = Geom2dGcc_CurveTool::Value(Cu1,pararg1(NbrSol));
900               pnttg2sol(NbrSol) = Geom2dGcc_CurveTool::Value(Cu2,pararg2(NbrSol));
901               par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
902                 pnttg1sol(NbrSol));
903               par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
904                 pnttg2sol(NbrSol));
905             }
906           }
907
908           WellDone = Standard_True;
909         }
910       }
911     }
912   }
913 }
914
915 //=========================================================================
916
917 Standard_Boolean Geom2dGcc_Circ2d2TanRadGeo::
918 IsDone () const { return WellDone; }
919
920 Standard_Integer Geom2dGcc_Circ2d2TanRadGeo::
921 NbSolutions () const { return NbrSol; }
922
923 gp_Circ2d Geom2dGcc_Circ2d2TanRadGeo::
924 ThisSolution (const Standard_Integer Index) const 
925 {
926   if (!WellDone) { throw StdFail_NotDone(); }
927   if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
928   return cirsol(Index);
929 }
930
931 void Geom2dGcc_Circ2d2TanRadGeo::
932 WhichQualifier(const Standard_Integer Index   ,
933                GccEnt_Position& Qualif1 ,
934                GccEnt_Position& Qualif2 ) const
935 {
936   if (!WellDone) { throw StdFail_NotDone(); }
937   else if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
938   else {
939     Qualif1 = qualifier1(Index);
940     Qualif2 = qualifier2(Index);
941   }
942 }
943
944 void Geom2dGcc_Circ2d2TanRadGeo::
945 Tangency1 (const Standard_Integer Index,
946            Standard_Real&   ParSol,
947            Standard_Real&   ParArg,
948            gp_Pnt2d&        PntSol) const{
949              if (!WellDone) { throw StdFail_NotDone(); }
950              else if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
951              else {
952                if (TheSame1(Index) == 0) {
953                  ParSol = par1sol(Index);
954                  ParArg = pararg1(Index);
955                  PntSol = gp_Pnt2d(pnttg1sol(Index));
956                }
957                else { throw StdFail_NotDone(); }
958              }
959 }
960
961 void Geom2dGcc_Circ2d2TanRadGeo::
962 Tangency2 (const Standard_Integer Index,
963            Standard_Real&   ParSol,
964            Standard_Real&   ParArg,
965            gp_Pnt2d&        PntSol) const{
966              if (!WellDone) { throw StdFail_NotDone(); }
967              else if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
968              else {
969                if (TheSame2(Index) == 0) {
970                  ParSol = par2sol(Index);
971                  ParArg = pararg2(Index);
972                  PntSol = gp_Pnt2d(pnttg2sol(Index));
973                }
974                else { throw StdFail_NotDone(); }
975              }
976 }
977
978 Standard_Boolean Geom2dGcc_Circ2d2TanRadGeo::
979 IsTheSame1 (const Standard_Integer Index) const
980 {
981   if (!WellDone) { throw StdFail_NotDone(); }
982   if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
983
984   if (TheSame1(Index) == 0) { return Standard_False; }
985   return Standard_True;
986 }
987
988 Standard_Boolean Geom2dGcc_Circ2d2TanRadGeo::
989 IsTheSame2 (const Standard_Integer Index) const
990 {
991   if (!WellDone) { throw StdFail_NotDone(); }
992   if (Index <= 0 ||Index > NbrSol) { throw Standard_OutOfRange(); }
993
994   if (TheSame2(Index) == 0) { return Standard_False; }
995   return Standard_True;
996 }
997