0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / GccAna / GccAna_Circ2d3Tan_4.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 // cas de 2 cercles concentriques JCT 28/11/97
16
17 #include <ElCLib.hxx>
18 #include <GccAna_Circ2d3Tan.hxx>
19 #include <GccAna_Circ2dBisec.hxx>
20 #include <GccAna_CircPnt2dBisec.hxx>
21 #include <GccEnt_BadQualifier.hxx>
22 #include <GccEnt_QualifiedCirc.hxx>
23 #include <GccEnt_QualifiedLin.hxx>
24 #include <GccInt_BCirc.hxx>
25 #include <GccInt_BElips.hxx>
26 #include <GccInt_BHyper.hxx>
27 #include <GccInt_BLine.hxx>
28 #include <GccInt_IType.hxx>
29 #include <gp_Circ2d.hxx>
30 #include <gp_Dir2d.hxx>
31 #include <gp_Lin2d.hxx>
32 #include <gp_Pnt2d.hxx>
33 #include <IntAna2d_AnaIntersection.hxx>
34 #include <IntAna2d_Conic.hxx>
35 #include <IntAna2d_IntPoint.hxx>
36 #include <Standard_OutOfRange.hxx>
37 #include <StdFail_NotDone.hxx>
38 #include <TColStd_Array1OfReal.hxx>
39
40 static Standard_Integer MaxSol = 20;
41 //=========================================================================
42 //   Creation of a circle tangent to two circles and a point.           +
43 //=========================================================================
44
45 GccAna_Circ2d3Tan::
46    GccAna_Circ2d3Tan (const GccEnt_QualifiedCirc& Qualified1 ,
47                       const GccEnt_QualifiedCirc& Qualified2 ,
48                       const gp_Pnt2d&             Point3     ,
49                       const Standard_Real         Tolerance  ):
50
51 //=========================================================================
52 //   Initialization of fields.                                           +
53 //=========================================================================
54
55    cirsol(1,MaxSol)     ,
56    qualifier1(1,MaxSol) ,
57    qualifier2(1,MaxSol) ,
58    qualifier3(1,MaxSol) ,
59    TheSame1(1,MaxSol)   ,
60    TheSame2(1,MaxSol)   ,
61    TheSame3(1,MaxSol)   ,
62    pnttg1sol(1,MaxSol)  ,
63    pnttg2sol(1,MaxSol)  ,
64    pnttg3sol(1,MaxSol)  ,
65    par1sol(1,MaxSol)    ,
66    par2sol(1,MaxSol)    ,
67    par3sol(1,MaxSol)    ,
68    pararg1(1,MaxSol)    ,
69    pararg2(1,MaxSol)    ,
70    pararg3(1,MaxSol)    
71 {
72
73    gp_Dir2d dirx(1.0,0.0);
74    Standard_Real Tol = Abs(Tolerance);
75    WellDone = Standard_False;
76    NbrSol = 0;
77    if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
78          Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
79        !(Qualified2.IsEnclosed() || Qualified2.IsEnclosing() || 
80          Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
81      throw GccEnt_BadQualifier();
82      return;
83    }
84
85 //=========================================================================
86 //   Processing.                                                          +
87 //=========================================================================
88
89    gp_Circ2d C1(Qualified1.Qualified());
90    gp_Circ2d C2(Qualified2.Qualified());
91    Standard_Real R1 = C1.Radius();
92    Standard_Real R2 = C2.Radius();
93    gp_Pnt2d center1(C1.Location());
94    gp_Pnt2d center2(C2.Location());
95
96    TColStd_Array1OfReal Radius(1,2);
97    GccAna_Circ2dBisec Bis1(C1,C2);
98    GccAna_CircPnt2dBisec Bis2(C1,Point3);
99    if (Bis1.IsDone() && Bis2.IsDone()) {
100      Standard_Integer nbsolution1 = Bis1.NbSolutions();
101      Standard_Integer nbsolution2 = Bis2.NbSolutions();
102      for (Standard_Integer i = 1 ; i <=  nbsolution1; i++) {
103        Handle(GccInt_Bisec) Sol1 = Bis1.ThisSolution(i);
104        GccInt_IType typ1 = Sol1->ArcType();
105        IntAna2d_AnaIntersection Intp;
106        for (Standard_Integer k = 1 ; k <=  nbsolution2; k++) {
107          Handle(GccInt_Bisec) Sol2 = Bis2.ThisSolution(k);
108          GccInt_IType typ2 = Sol2->ArcType();
109          if (typ1 == GccInt_Cir) {
110            if (typ2 == GccInt_Cir) {
111              Intp.Perform(Sol1->Circle(),Sol2->Circle());
112            }
113            else if (typ2 == GccInt_Lin) {
114              Intp.Perform(Sol2->Line(),Sol1->Circle());
115            }
116            else if (typ2 == GccInt_Hpr) {
117              Intp.Perform(Sol1->Circle(),IntAna2d_Conic(Sol2->Hyperbola()));
118            }
119            else if (typ2 == GccInt_Ell) {
120              Intp.Perform(Sol1->Circle(),IntAna2d_Conic(Sol2->Ellipse()));
121            }
122          }
123          else if (typ1 == GccInt_Ell) {
124            if (typ2 == GccInt_Cir) {
125              Intp.Perform(Sol2->Circle(),IntAna2d_Conic(Sol1->Ellipse()));
126            }
127            else if (typ2 == GccInt_Lin) {
128              Intp.Perform(Sol2->Line(),IntAna2d_Conic(Sol1->Ellipse()));
129            }
130            else if (typ2 == GccInt_Hpr) {
131              Intp.Perform(Sol1->Ellipse(),IntAna2d_Conic(Sol2->Hyperbola()));
132            }
133            else if (typ2 == GccInt_Ell) {
134              Intp.Perform(Sol1->Ellipse(),IntAna2d_Conic(Sol2->Ellipse()));
135            }
136          }
137          else if (typ1 == GccInt_Lin) {
138            if (typ2 == GccInt_Cir) {
139              Intp.Perform(Sol1->Line(),Sol2->Circle());
140            }
141            else if (typ2 == GccInt_Lin) {
142              Intp.Perform(Sol1->Line(),Sol2->Line());
143            }
144            else if (typ2 == GccInt_Hpr) {
145              Intp.Perform(Sol1->Line(),IntAna2d_Conic(Sol2->Hyperbola()));
146            }
147            else if (typ2 == GccInt_Ell) {
148              Intp.Perform(Sol1->Line(),IntAna2d_Conic(Sol2->Ellipse()));
149            }
150          }
151          else if (typ1 == GccInt_Hpr) {
152            if (typ2 == GccInt_Cir) {
153              Intp.Perform(Sol2->Circle(),IntAna2d_Conic(Sol1->Hyperbola()));
154            }
155            else if (typ2 == GccInt_Lin) {
156              Intp.Perform(Sol2->Line(),IntAna2d_Conic(Sol1->Hyperbola()));
157            }
158            else if (typ2 == GccInt_Hpr) {
159              Intp.Perform(Sol2->Hyperbola(),IntAna2d_Conic(Sol1->Hyperbola()));
160            }
161            else if (typ2 == GccInt_Ell) {
162              Intp.Perform(Sol2->Ellipse(),IntAna2d_Conic(Sol1->Hyperbola()));
163            }
164          }
165          if (Intp.IsDone()) {
166            if (!Intp.IsEmpty()) {
167              for (Standard_Integer j = 1 ; j <= Intp.NbPoints() ; j++) {
168                Standard_Real Rradius=0;
169                gp_Pnt2d Center(Intp.Point(j).Value());
170                Standard_Real dist1 = Center.Distance(center1);
171                Standard_Real dist2 = Center.Distance(center2);
172                Standard_Real dist3 = Center.Distance(Point3);
173                Standard_Integer nbsol1 = 0;
174                Standard_Integer nbsol2 = 0;
175                Standard_Integer nbsol3 = 0;
176                Standard_Boolean ok = Standard_False;
177                if (Qualified1.IsEnclosed()) {
178                  if (dist1-R1 < Tolerance) {
179                    Radius(1) = Abs(R1-dist1);
180                    nbsol1 = 1;
181                    ok = Standard_True;
182                  }
183                }
184                else if (Qualified1.IsOutside()) {
185                  if (R1-dist1 < Tolerance) {
186                    Radius(1) = Abs(R1-dist1);
187                    nbsol1 = 1;
188                    ok = Standard_True;
189                  }
190                }
191                else if (Qualified1.IsEnclosing()) {
192                  ok = Standard_True;
193                  nbsol1 = 1;
194                  Radius(1) = R1+dist1;
195                }
196                else if (Qualified1.IsUnqualified()) {
197                  ok = Standard_True;
198                  nbsol1 = 2;
199                  Radius(1) = Abs(R1-dist1);
200                  Radius(2) = R1+dist1;
201                }
202                if (Qualified2.IsEnclosed() && ok) {
203                  if (dist2-R2 < Tolerance) {
204                    for (Standard_Integer ii = 1 ; ii <= nbsol1 ; ii++) {
205                      if (Abs(Radius(ii)-Abs(R2-dist2)) < Tol) {
206                        Radius(1) = Abs(R2-dist2);
207                        ok = Standard_True;
208                        nbsol2 = 1;
209                      }
210                    }
211                  }
212                }
213                else if (Qualified2.IsOutside() && ok) {
214                  if (R2-dist2 < Tolerance) {
215                    for (Standard_Integer ii = 1 ; ii <= nbsol1 ; ii++) {
216                      if (Abs(Radius(ii)-Abs(R2-dist2)) < Tol) {
217                        Radius(1) = Abs(R2-dist2);
218                        ok = Standard_True;
219                        nbsol2 = 1;
220                      }
221                    }
222                  }
223                }
224                else if (Qualified2.IsEnclosing() && ok) {
225                  for (Standard_Integer ii = 1 ; ii <= nbsol1 ; ii++) {
226                    if (Abs(Radius(ii)-R2-dist2) < Tol) {
227                      Radius(1) = R2+dist2;
228                      ok = Standard_True;
229                      nbsol2 = 1;
230                    }
231                  }
232                }
233                else if (Qualified2.IsUnqualified() && ok) {
234                  for (Standard_Integer ii = 1 ; ii <= nbsol1 ; ii++) {
235                    if (Abs(Radius(ii)-Abs(R2-dist2)) < Tol) {
236                      Rradius = Abs(R2-dist2);
237                      ok = Standard_True;
238                      nbsol2++;
239                    }
240                    else if (Abs(Radius(ii)-R2-dist2) < Tol) {
241                      Rradius = R2+dist2;
242                      ok = Standard_True;
243                      nbsol2++;
244                    }
245                  }
246                  if (nbsol2 == 1) {
247                    Radius(1) = Rradius;
248                  }
249                  else if (nbsol2 == 2) {
250                    Radius(1) = Abs(R2-dist2);
251                    Radius(2) = R2+dist2;
252                  }
253                }
254                for (Standard_Integer ii = 1 ; ii <= nbsol2 ; ii++) {
255                  if (Abs(dist3-Radius(ii)) <= Tol) {
256                    nbsol3++;
257                    ok = Standard_True;
258                  }
259                }
260                if (ok) {
261                  for (Standard_Integer k1 = 1 ; k1 <= nbsol3 ; k1++) {
262                    NbrSol++;
263                    cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius(k1));
264 //                 ==========================================================
265                    Standard_Real distcc1 = Center.Distance(center1);
266                    if (!Qualified1.IsUnqualified()) { 
267                      qualifier1(NbrSol) = Qualified1.Qualifier();
268                    }
269                    else if (Abs(distcc1+Radius(k1)-R1) < Tol) {
270                      qualifier1(NbrSol) = GccEnt_enclosed;
271                    }
272                    else if (Abs(distcc1-R1-Radius(k1)) < Tol) {
273                      qualifier1(NbrSol) = GccEnt_outside;
274                    }
275                    else { qualifier1(NbrSol) = GccEnt_enclosing; }
276
277 //                 Standard_Real distcc2 = Center.Distance(center1);
278                    Standard_Real distcc2 = Center.Distance(center2);
279                    if (!Qualified2.IsUnqualified()) { 
280                      qualifier2(NbrSol) = Qualified2.Qualifier();
281                    }
282                    else if (Abs(distcc2+Radius(k1)-R2) < Tol) {
283                      qualifier2(NbrSol) = GccEnt_enclosed;
284                    }
285                    else if (Abs(distcc2-R2-Radius(k1)) < Tol) {
286                      qualifier2(NbrSol) = GccEnt_outside;
287                    }
288                    else { qualifier2(NbrSol) = GccEnt_enclosing; }
289                    qualifier3(NbrSol) = GccEnt_noqualifier;
290                    if (Center.Distance(center1) <= Tolerance &&
291                        Abs(Radius(k1)-R1) <= Tolerance) {
292                      TheSame1(NbrSol) = 1;
293                    }
294                    else {
295                      TheSame1(NbrSol) = 0;
296                      gp_Dir2d dc(center1.XY()-Center.XY());
297                      if (qualifier1(NbrSol) == GccEnt_enclosed)
298                        dc.Reverse(); // if tangent circle is inside the source circle, moving to edge of source circle
299                      pnttg1sol(NbrSol)=gp_Pnt2d(Center.XY()+Radius(k1)*dc.XY());
300                      par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
301                                                       pnttg1sol(NbrSol));
302                      pararg1(NbrSol)=ElCLib::Parameter(C1,
303                                                       pnttg1sol(NbrSol));
304                    }
305                    if (Center.Distance(center2) <= Tolerance &&
306                        Abs(Radius(k1)-R2) <= Tolerance) {
307                      TheSame2(NbrSol) = 1;
308                    }
309                    else {
310                      TheSame2(NbrSol) = 0;
311                      gp_Dir2d dc(center2.XY()-Center.XY());
312                      // case of concentric circles : 
313                      // 2nd tangency point is at the other side of the circle solution
314                      Standard_Real alpha = 1.;
315                      if (center1.Distance(center2)<=Tolerance) alpha = -1;
316                      pnttg2sol(NbrSol)=gp_Pnt2d(Center.XY()+alpha*Radius(k1)*dc.XY());
317                      par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
318                                                       pnttg2sol(NbrSol));
319                      pararg2(NbrSol)=ElCLib::Parameter(C2,pnttg2sol(NbrSol));
320                    }
321                    TheSame3(NbrSol) = 0;
322                    pnttg3sol(NbrSol) = Point3;
323                    par3sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
324                                                     pnttg3sol(NbrSol));
325                    pararg3(NbrSol) = 0.;
326                    WellDone = Standard_True;
327                    if (NbrSol==MaxSol) break;
328                  }
329                }
330              }
331            }
332            WellDone = Standard_True;
333            if (NbrSol==MaxSol) break;
334          }
335          if (NbrSol==MaxSol) break;
336        }
337        if (NbrSol==MaxSol) break;
338      }
339    }
340
341    // Debug to create the point on the solution circles.
342
343    Standard_Integer kk ;
344    for ( kk = 1; kk <= NbrSol; kk++) {
345      gp_Circ2d CC = cirsol(kk);
346      Standard_Real NR = CC.Location().Distance(Point3);
347      if (Abs(NR - CC.Radius()) > Tol) {
348        cirsol(kk).SetRadius(NR);
349      }
350    }
351
352    // Debug to eliminate multiple solution.
353    // this happens in case of intersection line hyperbola.
354    Standard_Real Tol2 = Tol*Tol;
355    for (kk = 1; kk <NbrSol; kk++) {
356      gp_Pnt2d PK = cirsol(kk).Location();
357      for (Standard_Integer ll = kk+1 ; ll <= NbrSol; ll++) {
358        gp_Pnt2d PL = cirsol(ll).Location();
359        if (PK.SquareDistance(PL) < Tol2) {
360          for (Standard_Integer mm = ll+1 ; mm <= NbrSol; mm++) {
361            cirsol(mm - 1)   = cirsol (mm);   
362            pnttg1sol(mm-1)  = pnttg1sol(mm);
363            pnttg2sol(mm-1)  = pnttg2sol(mm);
364            pnttg3sol(mm-1)  = pnttg3sol(mm);
365            par1sol(mm-1)    = par1sol(mm);
366            par2sol(mm-1)    = par2sol(mm);
367            par3sol(mm-1)    = par3sol(mm);
368            pararg1(mm-1)    = pararg1(mm);
369            pararg2(mm-1)    = pararg2(mm);
370            pararg3(mm-1)    = pararg3(mm);
371            qualifier1(mm-1) = qualifier1(mm);
372            qualifier2(mm-1) = qualifier2(mm);
373            qualifier3(mm-1) = qualifier3(mm);
374          }
375          NbrSol--;
376        }
377      }
378    }
379  }
380