0025861: Wrong result obtained by projection algorithm.
[occt.git] / src / Extrema / Extrema_ExtPS.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
17 #include <Extrema_ExtPS.ixx>
18 #include <Extrema_GenExtPS.hxx>
19 #include <StdFail_NotDone.hxx>
20 #include <Standard_NotImplemented.hxx>
21 #include <Precision.hxx>
22 #include <GeomAbs_CurveType.hxx>
23 #include <Adaptor3d_HSurfaceOfRevolution.hxx>
24 #include <Adaptor3d_HSurfaceOfLinearExtrusion.hxx>
25 #include <ElCLib.hxx>
26 #include <gp_Pnt.hxx>
27 #include <gp_Pln.hxx>
28 #include <gp_Cylinder.hxx>
29 #include <gp_Cone.hxx>
30 #include <gp_Sphere.hxx>
31 #include <gp_Torus.hxx>
32 #include <Extrema_ExtPExtS.hxx>
33 #include <Extrema_ExtPRevS.hxx>
34 #include <Extrema_POnSurf.hxx>
35 #include <GeomAbs_IsoType.hxx>
36
37 //=======================================================================
38 //function : IsoIsDeg
39 //purpose  : 
40 //=======================================================================
41
42 static Standard_Boolean IsoIsDeg  (const Adaptor3d_Surface& S,
43                                    const Standard_Real      Param,
44                                    const GeomAbs_IsoType    IT,
45                                    const Standard_Real      TolMin,
46                                    const Standard_Real      TolMax) 
47 {
48     Standard_Real U1=0.,U2=0.,V1=0.,V2=0.,T;
49     Standard_Boolean Along = Standard_True;
50     U1 = S.FirstUParameter();
51     U2 = S.LastUParameter();
52     V1 = S.FirstVParameter();
53     V2 = S.LastVParameter();
54     gp_Vec D1U,D1V;
55     gp_Pnt P;
56     Standard_Real Step,D1NormMax;
57     if (IT == GeomAbs_IsoV) 
58     {
59       if( !Precision::IsInfinite(U1) &&  !Precision::IsInfinite(U2) )
60       {
61         Step = (U2 - U1)/10;
62         if(Step < Precision::PConfusion()) {
63           return Standard_False;
64         }
65         D1NormMax=0.;
66
67         for (T=U1;T<=U2;T=T+Step) 
68         {
69           S.D1(T,Param,P,D1U,D1V);
70           D1NormMax=Max(D1NormMax,D1U.Magnitude());
71         }
72
73         if (D1NormMax >TolMax || D1NormMax < TolMin ) 
74           Along = Standard_False;
75       }
76     }
77     else 
78     {
79       if( !Precision::IsInfinite(V1) &&  !Precision::IsInfinite(V2) )
80       {
81         Step = (V2 - V1)/10;
82         if(Step < Precision::PConfusion()) {
83           return Standard_False;
84         }
85         D1NormMax=0.;
86         for (T=V1;T<=V2;T=T+Step) 
87         {
88           S.D1(Param,T,P,D1U,D1V);
89           D1NormMax=Max(D1NormMax,D1V.Magnitude());
90         }
91
92         if (D1NormMax >TolMax || D1NormMax < TolMin ) 
93           Along = Standard_False;
94       }
95
96
97
98     }
99     return Along;
100 }
101
102 //=======================================================================
103 //function : TreatSolution
104 //purpose  : 
105 //=======================================================================
106
107 void Extrema_ExtPS::TreatSolution (const Extrema_POnSurf& PS,
108                                    const Standard_Real Val)
109 {
110   Standard_Real U, V;
111   PS.Parameter(U, V);
112   if (myS->IsUPeriodic()) {
113     U = ElCLib::InPeriod(U, myuinf, myuinf + myS->UPeriod());
114     
115     // Handle trimmed surfaces.
116     if (U > myusup + mytolu)
117       U -= myS->UPeriod();
118     if (U < myuinf - mytolu)
119       U += myS->UPeriod();
120   }
121   if (myS->IsVPeriodic()) {
122     V = ElCLib::InPeriod(V, myvinf, myvinf + myS->VPeriod());
123
124     // Handle trimmed surfaces.
125     if (V > myvsup + mytolv)
126       V -= myS->VPeriod();
127     if (V < myvinf - mytolv)
128       V += myS->VPeriod();
129   }
130   if ((myuinf-U) <= mytolu && (U-myusup) <= mytolu &&
131       (myvinf-V) <= mytolv && (V-myvsup) <= mytolv) {
132     myPoints.Append(Extrema_POnSurf (U, V, PS.Value()));
133     mySqDist.Append(Val);
134   }
135 }
136
137
138 //=======================================================================
139 //function : Extrema_ExtPS
140 //purpose  : 
141 //=======================================================================
142
143 Extrema_ExtPS::Extrema_ExtPS()
144 {
145   myDone = Standard_False;
146 }
147
148
149 //=======================================================================
150 //function : Extrema_ExtPS
151 //purpose  : 
152 //=======================================================================
153
154 Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt&            theP,
155                               const Adaptor3d_Surface& theS,
156                               const Standard_Real      theTolU,
157                               const Standard_Real      theTolV,
158                               const Extrema_ExtFlag    theF,
159                               const Extrema_ExtAlgo    theA)
160 {
161   myExtPS.SetFlag (theF);
162   myExtPS.SetAlgo (theA);
163
164   Initialize (theS,
165               theS.FirstUParameter(),
166               theS.LastUParameter(),
167               theS.FirstVParameter(),
168               theS.LastVParameter(),
169               theTolU,
170               theTolV);
171
172   Perform (theP);
173 }
174
175 //=======================================================================
176 //function : Extrema_ExtPS
177 //purpose  : 
178 //=======================================================================
179
180 Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt&            theP,
181                               const Adaptor3d_Surface& theS,
182                               const Standard_Real      theUinf,
183                               const Standard_Real      theUsup,
184                               const Standard_Real      theVinf,
185                               const Standard_Real      theVsup,
186                               const Standard_Real      theTolU,
187                               const Standard_Real      theTolV,
188                               const Extrema_ExtFlag    theF,
189                               const Extrema_ExtAlgo    theA)
190 {
191   myExtPS.SetFlag (theF);
192   myExtPS.SetAlgo (theA);
193
194   Initialize (theS,
195               theUinf,
196               theUsup,
197               theVinf,
198               theVsup,
199               theTolU,
200               theTolV);
201
202   Perform (theP);
203 }
204
205
206 //=======================================================================
207 //function : Initialize
208 //purpose  : 
209 //=======================================================================
210
211 void Extrema_ExtPS::Initialize (const Adaptor3d_Surface& theS,
212                                 const Standard_Real      theUinf,
213                                 const Standard_Real      theUsup,
214                                 const Standard_Real      theVinf,
215                                 const Standard_Real      theVsup,
216                                 const Standard_Real      theTolU,
217                                 const Standard_Real      theTolV)
218 {
219   myS = (Adaptor3d_SurfacePtr)&theS;
220   myuinf = theUinf;
221   myusup = theUsup;
222   myvinf = theVinf;
223   myvsup = theVsup;
224
225   if (Precision::IsNegativeInfinite(myuinf)) myuinf = -1e10;
226   if (Precision::IsPositiveInfinite(myusup)) myusup = 1e10;
227   if (Precision::IsNegativeInfinite(myvinf)) myvinf = -1e10;
228   if (Precision::IsPositiveInfinite(myvsup)) myvsup = 1e10;
229
230   mytolu = theTolU;
231   mytolv = theTolV;
232   mytype = myS->GetType();
233
234   Standard_Boolean isB = ( myS->GetType() == GeomAbs_BSplineSurface ||
235                            myS->GetType() == GeomAbs_BezierSurface );
236
237   Standard_Integer nbU = (isB) ? 44 : 32;
238   Standard_Integer nbV = (isB) ? 44 : 32;
239
240   Standard_Boolean bUIsoIsDeg = Standard_False, bVIsoIsDeg = Standard_False;
241
242   if(myS->GetType() != GeomAbs_Plane) {
243     bUIsoIsDeg = IsoIsDeg(theS, myuinf, GeomAbs_IsoU, 0., 1.e-9) ||
244                  IsoIsDeg(theS, myusup, GeomAbs_IsoU, 0., 1.e-9);
245     bVIsoIsDeg = IsoIsDeg(theS, myvinf, GeomAbs_IsoV, 0., 1.e-9) ||
246                  IsoIsDeg(theS, myvsup, GeomAbs_IsoV, 0., 1.e-9);
247   }
248
249   if(bUIsoIsDeg) nbU = 300;
250   if(bVIsoIsDeg) nbV = 300;
251
252   myExtPS.Initialize(*myS, nbU, nbV, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
253
254   myExtPExtS.Nullify();
255   myExtPRevS.Nullify();
256 }
257
258 //=======================================================================
259 //function : Perform
260 //purpose  : 
261 //=======================================================================
262
263 void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
264 {
265   myPoints.Clear();
266   mySqDist.Clear();
267
268   switch (mytype)
269   {
270     case GeomAbs_Cylinder:
271       myExtPElS.Perform (thePoint, myS->Cylinder(), Precision::Confusion());
272       break;
273     case GeomAbs_Plane:
274       myExtPElS.Perform (thePoint, myS->Plane(), Precision::Confusion());
275       break;
276     case GeomAbs_Cone:
277       myExtPElS.Perform (thePoint, myS->Cone(), Precision::Confusion());
278       break;
279     case GeomAbs_Sphere:
280       myExtPElS.Perform (thePoint, myS->Sphere(), Precision::Confusion());
281       break;
282     case GeomAbs_Torus:
283       myExtPElS.Perform (thePoint, myS->Torus(), Precision::Confusion());
284       break;
285
286     case GeomAbs_SurfaceOfExtrusion:
287     {
288       if (myExtPExtS.IsNull())
289       {
290         Handle(Adaptor3d_HSurfaceOfLinearExtrusion) aS (new Adaptor3d_HSurfaceOfLinearExtrusion (
291           Adaptor3d_SurfaceOfLinearExtrusion (myS->BasisCurve(), myS->Direction())));
292
293         myExtPExtS = new Extrema_ExtPExtS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
294       }
295       else
296       {
297         myExtPExtS->Perform (thePoint);
298       }
299
300       myDone = myExtPExtS->IsDone();
301       if (myDone)
302       {
303         for (Standard_Integer anIdx = 1; anIdx <= myExtPExtS->NbExt(); ++anIdx)
304         {
305           TreatSolution (myExtPExtS->Point (anIdx), myExtPExtS->SquareDistance (anIdx));
306         }
307       }
308
309       return;
310     }
311
312     case GeomAbs_SurfaceOfRevolution:
313     {
314       if (myExtPRevS.IsNull())
315       {
316         Handle(Adaptor3d_HSurfaceOfRevolution) aS (new Adaptor3d_HSurfaceOfRevolution (
317           Adaptor3d_SurfaceOfRevolution (myS->BasisCurve(), myS->AxeOfRevolution())));
318
319         myExtPRevS = new Extrema_ExtPRevS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
320       }
321       else
322       {
323         myExtPRevS->Perform (thePoint);
324       }
325
326       myDone = myExtPRevS->IsDone();
327       if (myDone)
328       {
329         for (Standard_Integer anIdx = 1; anIdx <= myExtPRevS->NbExt(); ++anIdx)
330         {
331           TreatSolution (myExtPRevS->Point (anIdx), myExtPRevS->SquareDistance (anIdx));
332         }
333       }
334
335       return;
336     }
337
338     default:
339     {
340       myExtPS.Perform (thePoint);
341       myDone = myExtPS.IsDone();
342       if (myDone)
343       {
344         for (Standard_Integer anIdx = 1; anIdx <= myExtPS.NbExt(); ++anIdx)
345         {
346           TreatSolution (myExtPS.Point (anIdx), myExtPS.SquareDistance (anIdx));
347         }
348       }
349       return;
350     }
351   }
352
353   myDone = myExtPElS.IsDone();
354   if (myDone)
355   {
356     for (Standard_Integer anIdx = 1; anIdx <= myExtPElS.NbExt(); ++anIdx)
357     {
358       TreatSolution (myExtPElS.Point (anIdx), myExtPElS.SquareDistance (anIdx));
359     }
360   }
361 }
362
363
364 Standard_Boolean Extrema_ExtPS::IsDone() const
365 {
366   return myDone;
367 }
368
369
370 Standard_Real Extrema_ExtPS::SquareDistance(const Standard_Integer N) const
371 {
372   if(!myDone) StdFail_NotDone::Raise();
373   if ((N < 1) || (N > mySqDist.Length())) Standard_OutOfRange::Raise();
374   return mySqDist.Value(N);
375 }
376
377
378 Standard_Integer Extrema_ExtPS::NbExt() const
379 {
380   if(!myDone) StdFail_NotDone::Raise();
381   return mySqDist.Length();
382 }
383
384
385 const Extrema_POnSurf& Extrema_ExtPS::Point(const Standard_Integer N) const
386 {
387   if(!myDone) StdFail_NotDone::Raise();
388   return myPoints.Value(N);
389 }
390
391
392 void Extrema_ExtPS::TrimmedSquareDistances(Standard_Real& dUfVf,
393                                       Standard_Real& dUfVl,
394                                       Standard_Real& dUlVf,
395                                       Standard_Real& dUlVl,
396                                       gp_Pnt&        PUfVf,
397                                       gp_Pnt&        PUfVl,
398                                       gp_Pnt&        PUlVf,
399                                       gp_Pnt&        PUlVl) const
400 {
401   dUfVf = d11;
402   dUfVl = d12;
403   dUlVf = d21;
404   dUlVl = d22;
405   PUfVf = P11;
406   PUfVl = P12;
407   PUlVf = P21;
408   PUlVl = P22;
409 }
410
411 void Extrema_ExtPS::SetFlag(const Extrema_ExtFlag F)
412 {
413   myExtPS.SetFlag(F);
414 }
415
416 void Extrema_ExtPS::SetAlgo(const Extrema_ExtAlgo A)
417 {
418   myExtPS.SetAlgo(A);
419 }