0023948: Wrong intersection between a surface of revolution and a plane.
[occt.git] / src / GccAna / GccAna_Circ2d2TanOn_1.cxx
1 // Created on: 1992-01-02
2 // Created by: Remi GILET
3 // Copyright (c) 1992-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <GccAna_Circ2d2TanOn.jxx>
18
19 #include <ElCLib.hxx>
20 #include <gp_Dir2d.hxx>
21 #include <gp_Ax2d.hxx>
22 #include <IntAna2d_AnaIntersection.hxx>
23 #include <IntAna2d_IntPoint.hxx>
24 #include <GccAna_CircLin2dBisec.hxx>
25 #include <GccInt_IType.hxx>
26 #include <GccInt_BCirc.hxx>
27 #include <IntAna2d_Conic.hxx>
28 #include <GccEnt_BadQualifier.hxx>
29
30 //=========================================================================
31 //   Creation of a circle tangent to Circle C1 and a straight line L2.    +
32 //                        centered on a straight line.                    +
33 //  We start by making difference between cases that we are going to      +
34 //  proceess separately.                                            +
35 //  In general case:                                                  +
36 //  ====================                                                  +
37 //  We calculate bissectrices to C1 and L2 that give us            +
38 //  all possibles locations of centers of all circles tangent to C1 and L2+                                                  +
39 //  We intersect these bissectrices with straight line OnLine which gives   +
40 //  us points among which we'll choose the solutions.   +
41 //  The choices are made basing on Qualifiers of C1 and L2.  +
42 //=========================================================================
43
44 GccAna_Circ2d2TanOn::
45    GccAna_Circ2d2TanOn (const GccEnt_QualifiedCirc& Qualified1  , 
46                         const GccEnt_QualifiedLin&  Qualified2  , 
47                         const gp_Lin2d&             OnLine      ,
48                         const Standard_Real         Tolerance   ):
49    cirsol(1,4)     ,
50    qualifier1(1,4) ,
51    qualifier2(1,4),
52    TheSame1(1,4)   ,
53    TheSame2(1,4)   ,
54    pnttg1sol(1,4)  ,
55    pnttg2sol(1,4)  ,
56    pntcen(1,4)     ,
57    par1sol(1,4)    ,
58    par2sol(1,4)    ,
59    pararg1(1,4)    ,
60    pararg2(1,4)    ,
61    parcen3(1,4)
62 {
63
64    TheSame1.Init(0);
65    TheSame2.Init(0);
66    WellDone = Standard_False;
67    NbrSol = 0;
68    if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
69          Qualified1.IsOutside() || Qualified1.IsUnqualified()) ||
70        !(Qualified2.IsEnclosed() ||
71          Qualified2.IsOutside() || Qualified2.IsUnqualified())) {
72      GccEnt_BadQualifier::Raise();
73      return;
74    }
75    Standard_Real Tol = Abs(Tolerance);
76    Standard_Real Radius=0;
77    Standard_Boolean ok = Standard_False;
78    gp_Dir2d dirx(1.,0.);
79    gp_Circ2d C1 = Qualified1.Qualified();
80    gp_Lin2d  L2 = Qualified2.Qualified();
81    Standard_Real R1 = C1.Radius();
82    gp_Pnt2d center1(C1.Location());
83    gp_Pnt2d origin2(L2.Location());
84    gp_Dir2d dirL2(L2.Direction());
85    gp_Dir2d normL2(-dirL2.Y(),dirL2.X());
86
87 //=========================================================================
88 //   Processing of limit cases.                                          +
89 //=========================================================================
90
91    Standard_Real distcl = OnLine.Distance(center1);
92    gp_Pnt2d pinterm(center1.XY()+distcl*
93                     gp_XY(-OnLine.Direction().Y(),OnLine.Direction().X()));
94    if (OnLine.Distance(pinterm) > Tolerance) {
95      pinterm = gp_Pnt2d(center1.XY()+distcl*
96                         gp_XY(-OnLine.Direction().Y(),OnLine.Direction().X()));
97    }
98    Standard_Real dist2 = L2.Distance(pinterm);
99    if (Qualified1.IsEnclosed() || Qualified1.IsOutside()) {
100      if (Abs(distcl-R1-dist2) <= Tol) { ok = Standard_True; }
101    }
102    else if (Qualified1.IsEnclosing()) {
103      if (Abs(dist2-distcl-R1) <= Tol) { ok = Standard_True; }
104    }
105    else if (Qualified1.IsUnqualified()) { ok = Standard_True; }
106    else { 
107      GccEnt_BadQualifier::Raise();
108      return;
109    }
110    if (ok) {
111      if (Qualified2.IsOutside()) {
112        gp_Pnt2d pbid(pinterm.XY()+dist2*gp_XY(-dirL2.Y(),dirL2.X()));
113        if (L2.Distance(pbid) <= Tol) { WellDone = Standard_True; }
114      }
115      else if (Qualified2.IsEnclosed()) {
116        gp_Pnt2d pbid(pinterm.XY()-dist2*gp_XY(-dirL2.Y(),dirL2.X()));
117        if (L2.Distance(pbid) <= Tol) { WellDone = Standard_True; }
118      }
119      else if (Qualified2.IsUnqualified()) { WellDone = Standard_False; }
120      else { 
121        GccEnt_BadQualifier::Raise();
122        return;
123      }
124    }
125    if (WellDone) {
126      NbrSol++;
127      cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(pinterm,dirx),dist2);
128 //   =======================================================
129      gp_Dir2d dc1(center1.XY()-pinterm.XY());
130      gp_Dir2d dc2(origin2.XY()-pinterm.XY());
131      Standard_Real distcc1 = pinterm.Distance(center1);
132      if (!Qualified1.IsUnqualified()) { 
133        qualifier1(NbrSol) = Qualified1.Qualifier();
134      }
135      else if (Abs(distcc1+dist2-R1) < Tol) {
136        qualifier1(NbrSol) = GccEnt_enclosed;
137      }
138      else if (Abs(distcc1-R1-dist2) < Tol) {
139        qualifier1(NbrSol) = GccEnt_outside;
140      }
141      else { qualifier1(NbrSol) = GccEnt_enclosing; }
142      if (!Qualified2.IsUnqualified()) { 
143        qualifier2(NbrSol) = Qualified2.Qualifier();
144      }
145      else if (dc2.Dot(normL2) > 0.0) {
146        qualifier2(NbrSol) = GccEnt_outside;
147      }
148      else { qualifier2(NbrSol) = GccEnt_enclosed; }
149
150      Standard_Real sign = dc2.Dot(gp_Dir2d(-dirL2.Y(),dirL2.X()));
151      dc2 = gp_Dir2d(sign*gp_XY(-dirL2.Y(),dirL2.X()));
152      pnttg1sol(NbrSol) = gp_Pnt2d(pinterm.XY()+dist2*dc1.XY());
153      pnttg2sol(NbrSol) = gp_Pnt2d(pinterm.XY()+dist2*dc2.XY());
154      par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),pnttg1sol(NbrSol));
155      pararg1(NbrSol)=ElCLib::Parameter(C1,pnttg1sol(NbrSol));
156      par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),pnttg2sol(NbrSol));
157      pararg2(NbrSol)=ElCLib::Parameter(L2,pnttg2sol(NbrSol));
158      pntcen(NbrSol) = cirsol(NbrSol).Location();
159      parcen3(NbrSol)=ElCLib::Parameter(OnLine,pntcen(NbrSol));
160      return;
161    }
162
163 //=========================================================================
164 //   General case.                                                        +
165 //=========================================================================
166
167    GccAna_CircLin2dBisec Bis(C1,L2);
168    if (Bis.IsDone()) {
169      Standard_Integer nbsolution = Bis.NbSolutions();
170      for (Standard_Integer i = 1 ; i <=  nbsolution; i++) {
171        Handle(GccInt_Bisec) Sol = Bis.ThisSolution(i);
172        GccInt_IType type = Sol->ArcType();
173        IntAna2d_AnaIntersection Intp;
174        if (type == GccInt_Lin) {
175          Intp.Perform(OnLine,Sol->Line());
176        }
177        else if (type == GccInt_Par) {
178          Intp.Perform(OnLine,IntAna2d_Conic(Sol->Parabola()));
179        }
180        if (Intp.IsDone()) {
181          if (!Intp.IsEmpty()) {
182            for (Standard_Integer j = 1 ; j <= Intp.NbPoints() ; j++) {
183              gp_Pnt2d Center(Intp.Point(j).Value());
184              Standard_Real dist1 = Center.Distance(center1);
185              dist2 = L2.Distance(Center);
186 //           Standard_Integer nbsol = 1;
187              ok = Standard_False;
188              if (Qualified1.IsEnclosed()) {
189                if (dist1-R1 < Tolerance) {
190                  if (Abs(Abs(R1-dist1)-dist2)<Tolerance) { ok=Standard_True; }
191                }
192              }
193              else if (Qualified1.IsOutside()) {
194                if (R1-dist1 < Tolerance) {
195                  if (Abs(Abs(R1-dist1)-dist2)<Tolerance) { ok=Standard_True; }
196                }
197              }
198              else if (Qualified1.IsEnclosing() || Qualified1.IsUnqualified()) {
199                ok = Standard_True;
200              }
201              if (Qualified2.IsEnclosed() && ok) {
202                if ((((origin2.X()-Center.X())*(-dirL2.Y()))+
203                     ((origin2.Y()-Center.Y())*(dirL2.X())))<=0){
204                  ok = Standard_True;
205                  Radius = dist2;
206                }
207              }
208              else if (Qualified2.IsOutside() && ok) {
209                if ((((origin2.X()-Center.X())*(-dirL2.Y()))+
210                     ((origin2.Y()-Center.Y())*(dirL2.X())))>=0){
211                  ok = Standard_True;
212                  Radius = dist2;
213                }
214              }
215              else if (Qualified2.IsUnqualified() && ok) {
216                ok = Standard_True;
217                Radius = dist2;
218              }
219              if (ok) {
220                NbrSol++;
221                cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
222 //             =======================================================
223                gp_Dir2d dc1(center1.XY()-Center.XY());
224                gp_Dir2d dc2(origin2.XY()-Center.XY());
225                Standard_Real distcc1 = Center.Distance(center1);
226                if (!Qualified1.IsUnqualified()) { 
227                  qualifier1(NbrSol) = Qualified1.Qualifier();
228                }
229                else if (Abs(distcc1+Radius-R1) < Tol) {
230                  qualifier1(NbrSol) = GccEnt_enclosed;
231                }
232                else if (Abs(distcc1-R1-Radius) < Tol) {
233                  qualifier1(NbrSol) = GccEnt_outside;
234                }
235                else { qualifier1(NbrSol) = GccEnt_enclosing; }
236                if (!Qualified2.IsUnqualified()) { 
237                  qualifier2(NbrSol) = Qualified2.Qualifier();
238                }
239                else if (dc2.Dot(normL2) > 0.0) {
240                  qualifier2(NbrSol) = GccEnt_outside;
241                }
242                else { qualifier2(NbrSol) = GccEnt_enclosed; }
243                if (Center.Distance(center1) <= Tolerance &&
244                    Abs(Radius-C1.Radius()) <= Tolerance) {
245                  TheSame1(NbrSol) = 1;
246                  }
247                else {
248                  TheSame1(NbrSol) = 0;
249                  pnttg1sol(NbrSol) = gp_Pnt2d(Center.XY()+Radius*dc1.XY());
250                  par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
251                                                         pnttg1sol(NbrSol));
252                  pararg1(NbrSol)=ElCLib::Parameter(C1,pnttg1sol(NbrSol));
253                }
254                TheSame2(NbrSol) = 0;
255                Standard_Real sign = dc2.Dot(gp_Dir2d(-dirL2.Y(),dirL2.X()));
256                dc2 = gp_Dir2d(sign*gp_XY(-dirL2.Y(),dirL2.X()));
257                pnttg2sol(NbrSol) = gp_Pnt2d(Center.XY()+Radius*dc2.XY());
258                par2sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),
259                                                       pnttg2sol(NbrSol));
260                pararg2(NbrSol)=ElCLib::Parameter(L2,pnttg2sol(NbrSol));
261                pntcen(NbrSol) = Center;
262                parcen3(NbrSol)=ElCLib::Parameter(OnLine,pntcen(NbrSol));
263              }
264            }
265          }
266          WellDone = Standard_True;
267        }
268      }
269    }
270  }
271
272
273
274
275
276