0023948: Wrong intersection between a surface of revolution and a plane.
[occt.git] / src / GccAna / GccAna_Circ2dTanCen.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 //    Creation of a circle tangent to an element and having center in a point    +
17 //================================================================================
18
19 #include <GccAna_Circ2dTanCen.ixx>
20
21 #include <ElCLib.hxx>
22 #include <gp_Circ2d.hxx>
23 #include <gp_Lin2d.hxx>
24 #include <gp.hxx>
25 #include <gp_Dir2d.hxx>
26 #include <Standard_OutOfRange.hxx>
27 #include <StdFail_NotDone.hxx>
28 #include <GccEnt_BadQualifier.hxx>
29
30 //========================================================================
31 //     Creation of a circle tangent to a circle with center in a point.      +
32 //   - Calculate the distance between the center of the circle and the point of  +
33 //     center : dist                                                     +
34 //   - Check that this distance is compatible with the qualifier of the circle.                                                        +
35 //       Si yes, the radius of the solution will be :                           +
36 //          C1.Radius()-dist if the qualifier is Enclosed.              +
37 //          C1.Radius()+dist if the qualifier is Enclosing.             +
38 //          dist-C1.Radius() if the qualifier is Outside.               +
39 //          a mix of these values if the qualifier is Unqualified.  +
40 //========================================================================
41
42
43 GccAna_Circ2dTanCen::
44    GccAna_Circ2dTanCen (const GccEnt_QualifiedCirc& Qualified1,
45                         const gp_Pnt2d&             Pcenter   ,
46                         const Standard_Real                  Tolerance ):
47
48 //========================================================================
49 //   Initialization of fields.                                          +
50 //========================================================================
51
52    cirsol(1,2)   ,
53    qualifier1(1,2) ,
54    TheSame1(1,2) ,
55    pnttg1sol(1,2),
56    par1sol(1,2),
57    pararg1(1,2)
58 {
59
60    NbrSol = 0;
61    Standard_Real Radius = 0.0;
62    WellDone = Standard_False;
63    if (!(Qualified1.IsEnclosed() || Qualified1.IsEnclosing() || 
64          Qualified1.IsOutside() || Qualified1.IsUnqualified())) {
65      GccEnt_BadQualifier::Raise();
66      return;
67    }
68    gp_Dir2d dirx(1.0,0.0);
69    Standard_Real Tol = Abs(Tolerance);
70    gp_Circ2d C1 = Qualified1.Qualified();
71    Standard_Real R1 = C1.Radius();
72    gp_Pnt2d center1(C1.Location());
73    Standard_Real dist;
74    Standard_Integer signe = 0;
75    Standard_Integer signe1 = 0;
76
77    if (!Qualified1.IsUnqualified()) {
78      dist = Pcenter.Distance(center1);
79      if (Qualified1.IsEnclosed()) {
80 //   ============================
81        if (dist-R1 <= Tol) {
82          Radius = Abs(R1-dist);
83          signe = 1;
84        }
85        else { WellDone = Standard_True; }
86      }
87      else if (Qualified1.IsEnclosing()) {
88 //   =================================
89        Radius = R1+dist;
90        signe = -1;
91      }
92      else if (Qualified1.IsOutside()) {
93 //   ===============================
94        if (dist < R1-Tol) { WellDone = Standard_True; }
95        else {
96          Radius = Abs(R1-dist);
97          signe = -1;
98        }
99      }
100      if (signe != 0) {
101        NbrSol++;
102        cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Pcenter,dirx),Radius);
103 //     ========================================================
104        qualifier1(NbrSol) = Qualified1.Qualifier();
105        if (dist <= gp::Resolution()) { TheSame1(NbrSol) = 1; }
106        else {
107          TheSame1(NbrSol) = 0;
108          gp_Dir2d d(Pcenter.X()-center1.X(),Pcenter.Y()-center1.Y());
109          pnttg1sol(NbrSol) = gp_Pnt2d(Pcenter.XY()+signe*Radius*d.XY());
110          par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),pnttg1sol(NbrSol));
111          pararg1(NbrSol)=ElCLib::Parameter(C1,pnttg1sol(NbrSol));
112        }
113        WellDone = Standard_True;
114      }
115    }
116    else {
117 // ====
118      dist = Pcenter.Distance(center1);
119      if (dist >= gp::Resolution()) {
120        signe = 1;
121        for (Standard_Integer i = 1; i <= 2 ; i++) {
122          signe = -signe;
123          if (R1-dist <= 0.) {
124            signe1 = -1;
125          }
126          else {
127            signe1 = -signe;
128          }
129          Radius = Abs(R1+signe*dist);
130          NbrSol++;
131          cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Pcenter,dirx),Radius);
132 //       ========================================================
133          Standard_Real distcc1 = Pcenter.Distance(center1);
134          if (!Qualified1.IsUnqualified()) { 
135            qualifier1(NbrSol) = Qualified1.Qualifier();
136          }
137          else if (Abs(distcc1+Radius-R1) < Tol) {
138            qualifier1(NbrSol) = GccEnt_enclosed;
139          }
140          else if (Abs(distcc1-R1-Radius) < Tol) {
141            qualifier1(NbrSol) = GccEnt_outside;
142          }
143          else { qualifier1(NbrSol) = GccEnt_enclosing; }
144          TheSame1(NbrSol) = 0;
145          WellDone = Standard_True;
146          gp_Dir2d d(Pcenter.X()-center1.X(),Pcenter.Y()-center1.Y());
147          pnttg1sol(NbrSol) = gp_Pnt2d(Pcenter.XY()+signe1*Radius*d.XY());
148          par1sol(NbrSol)=ElCLib::Parameter(cirsol(NbrSol),pnttg1sol(NbrSol));
149          pararg1(NbrSol)=ElCLib::Parameter(C1,pnttg1sol(NbrSol));
150        }
151      }
152      else {
153        NbrSol++;
154        cirsol(NbrSol) = gp_Circ2d(C1);
155 //     ==============================
156        qualifier1(1) = Qualified1.Qualifier();
157        TheSame1(NbrSol) = 1;
158        WellDone = Standard_True;
159      }
160    }
161  }
162
163 //=========================================================================
164 //   Circle tangent to line Linetan and center in a point Pcenter.    +
165 //   Calculate the distance from the point to the line ==> Radius.                +
166 //   Create the circle with center Pcenter of radius Radius.                  +
167 //=========================================================================
168
169 GccAna_Circ2dTanCen::
170    GccAna_Circ2dTanCen (const gp_Lin2d&            Linetan    ,
171                         const gp_Pnt2d&            Pcenter    ):
172
173 //=========================================================================
174 //   Initialisation of fields.                                           +
175 //=========================================================================
176
177    cirsol(1,1)   ,
178    qualifier1(1,1),
179    TheSame1(1,1) ,
180    pnttg1sol(1,1),
181    par1sol(1,1),
182    pararg1(1,1) 
183 {
184
185    gp_Dir2d dirx(1.0,0.0);
186    Standard_Real rayon = Linetan.Distance(Pcenter);
187    cirsol(1) = gp_Circ2d(gp_Ax2d(Pcenter,dirx),rayon);
188 // ==================================================
189    qualifier1(1) = GccEnt_noqualifier;
190    TheSame1(1) = 0;
191    Standard_Real xloc = Linetan.Location().X();
192    Standard_Real yloc = Linetan.Location().Y();
193    Standard_Real xdir = Linetan.Direction().X();
194    Standard_Real ydir = Linetan.Direction().Y();
195
196    if (gp_Dir2d(xloc-Pcenter.X(),yloc-Pcenter.Y())
197                .Dot(gp_Dir2d(-ydir,xdir)) > 0.0) {
198      pnttg1sol(1) = gp_Pnt2d(Pcenter.XY()+rayon*gp_XY(-ydir,xdir));
199      par1sol(1)=ElCLib::Parameter(cirsol(1),pnttg1sol(1));
200      pararg1(1)=ElCLib::Parameter(Linetan,pnttg1sol(1));
201    }
202    else {
203      pnttg1sol(1) = gp_Pnt2d(Pcenter.XY()+rayon*gp_XY(ydir,-xdir));
204      par1sol(1)=ElCLib::Parameter(cirsol(1),pnttg1sol(1));
205      pararg1(1)=ElCLib::Parameter(Linetan,pnttg1sol(1));
206    }
207    NbrSol = 1;
208    WellDone = Standard_True;
209  }
210
211 //=========================================================================
212 //   Circle tangent to point Point1 and centered in a point Pcenter.      +
213 //   Calculate the distance from Pcenter to Point1 ==> Radius.                +
214 //   Create the circle with center Pcenter of radius Radius.                  +
215 //=========================================================================
216
217 GccAna_Circ2dTanCen::
218    GccAna_Circ2dTanCen (const gp_Pnt2d&            Point1     ,
219                         const gp_Pnt2d&            Pcenter    ):
220
221 //=========================================================================
222 //   Initialisation of fields.                                           +
223 //=========================================================================
224
225    cirsol(1,1)   ,
226    qualifier1(1,1),
227    TheSame1(1,1) ,
228    pnttg1sol(1,1),
229    par1sol(1,1)  ,
230    pararg1(1,1)  
231 {
232
233    gp_Dir2d dirx(1.0,0.0);
234    Standard_Real rayon = Point1.Distance(Pcenter);
235    cirsol(1) = gp_Circ2d(gp_Ax2d(Pcenter,dirx),rayon);
236 // =================================================
237    qualifier1(1) = GccEnt_noqualifier;
238    TheSame1(1) = 0;
239    pnttg1sol(1) = Point1;
240    par1sol(1)=ElCLib::Parameter(cirsol(1),pnttg1sol(1));
241    pararg1(1) = 0.0;
242    NbrSol = 1;
243    WellDone = Standard_True;
244  }
245
246 //=========================================================================
247
248 Standard_Boolean GccAna_Circ2dTanCen::
249    IsDone () const { return WellDone; }
250
251 Standard_Integer GccAna_Circ2dTanCen::
252    NbSolutions () const { return NbrSol; }
253
254 gp_Circ2d GccAna_Circ2dTanCen::
255    ThisSolution (const Standard_Integer Index) const 
256 {
257   if (Index > NbrSol || Index <= 0) { Standard_OutOfRange::Raise(); }
258   return cirsol(Index);
259 }
260
261 void GccAna_Circ2dTanCen::
262   WhichQualifier(const Standard_Integer Index   ,
263                        GccEnt_Position& Qualif1 ) const
264 {
265   if (!WellDone) { StdFail_NotDone::Raise(); }
266    else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
267    else {
268      Qualif1 = qualifier1(Index);
269    }
270 }
271
272 void GccAna_Circ2dTanCen::
273    Tangency1 (const Standard_Integer Index,
274               Standard_Real& ParSol,
275               Standard_Real& ParArg,
276               gp_Pnt2d& PntSol) const{
277    if (!WellDone) { StdFail_NotDone::Raise(); }
278    else if (Index <= 0 ||Index > NbrSol) { Standard_OutOfRange::Raise(); }
279    else {
280      if (TheSame1(Index) == 0) {
281        PntSol = gp_Pnt2d(pnttg1sol(Index));
282        ParSol = par1sol(Index);
283        ParArg = pararg1(Index);
284      }
285      else { StdFail_NotDone::Raise(); }
286    }
287  }
288
289 Standard_Boolean GccAna_Circ2dTanCen::
290    IsTheSame1 (const Standard_Integer Index) const
291 {
292   if (!WellDone) 
293     StdFail_NotDone::Raise();
294   if (Index <= 0 ||Index > NbrSol) 
295     Standard_OutOfRange::Raise();
296  
297   if (TheSame1(Index) == 0) 
298     return Standard_False;
299
300   return Standard_True;
301 }