0024200: Wrong result obtained by Exterma Curve/Curve
[occt.git] / src / Extrema / Extrema_ExtCS.cxx
1 // Created on: 1995-07-18
2 // Created by: Modelistation
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22 //  Modified by skv - Thu Jul  7 12:29:34 2005 OCC9134
23
24 #include <Extrema_ExtCS.ixx>
25 #include <Extrema_GenExtCS.hxx>
26 #include <StdFail_NotDone.hxx>
27 #include <Standard_NotImplemented.hxx>
28 #include <StdFail_InfiniteSolutions.hxx>
29 #include <Precision.hxx>
30 #include <GeomAbs_CurveType.hxx>
31 #include <gp_Pnt.hxx>
32 #include <gp_Pln.hxx>
33 #include <gp_Cylinder.hxx>
34 #include <gp_Cone.hxx>
35 #include <gp_Sphere.hxx>
36 #include <gp_Torus.hxx>
37 #include <gp_Lin.hxx>
38
39 #include <ElCLib.hxx>
40 #include <Extrema_ExtPElC.hxx>
41 #include <Bnd_Box.hxx>
42 #include <BndLib_AddSurface.hxx>
43 #include <Extrema_ExtPElS.hxx>
44 #include <TColStd_Array1OfReal.hxx>
45 #include <Extrema_ExtPS.hxx>
46
47 Extrema_ExtCS::Extrema_ExtCS() 
48 {
49   myDone = Standard_False;
50 }
51
52 Extrema_ExtCS::Extrema_ExtCS(const Adaptor3d_Curve&   C,
53                              const Adaptor3d_Surface& S,
54                              const Standard_Real    TolC,
55                              const Standard_Real    TolS)
56
57 {
58   Initialize(S, S.FirstUParameter(), S.LastUParameter(), 
59              S.FirstVParameter(), S.LastVParameter(), 
60              TolC, TolS);
61   Perform(C, C.FirstParameter(), C.LastParameter());
62 }
63
64 Extrema_ExtCS::Extrema_ExtCS(const Adaptor3d_Curve&   C,
65                              const Adaptor3d_Surface& S,
66                              const Standard_Real    UCinf,
67                              const Standard_Real    UCsup,
68                              const Standard_Real    Uinf,       
69                              const Standard_Real    Usup,
70                              const Standard_Real    Vinf,       
71                              const Standard_Real    Vsup,
72                              const Standard_Real    TolC,
73                              const Standard_Real    TolS)
74
75 {
76   Initialize(S, Uinf, Usup, Vinf, Vsup, TolC, TolS);
77   Perform(C, UCinf, UCsup);
78 }
79
80
81 void Extrema_ExtCS::Initialize(const Adaptor3d_Surface& S,
82                                const Standard_Real    Uinf,     
83                                const Standard_Real    Usup,
84                                const Standard_Real    Vinf,     
85                                const Standard_Real    Vsup,
86                                const Standard_Real    TolC,
87                                const Standard_Real    TolS)
88 {
89   myS = (Adaptor3d_SurfacePtr)&S;
90   myIsPar = Standard_False;
91   myuinf  = Uinf;
92   myusup  = Usup;
93   myvinf  = Vinf;
94   myvsup  = Vsup;
95   mytolC  = TolC;
96   mytolS  = TolS;
97   myStype  = myS->GetType();
98 }
99
100                                 
101 void Extrema_ExtCS::Perform(const Adaptor3d_Curve& C,
102                             const Standard_Real  Uinf,
103                             const Standard_Real  Usup)
104 {
105   myucinf = Uinf;
106   myucsup = Usup;
107   myPOnS.Clear();
108   myPOnC.Clear();
109   mySqDist.Clear();
110   Standard_Integer i, j;
111   Standard_Integer NbT, NbU, NbV;
112   NbT = NbU = NbV = 10;
113   GeomAbs_CurveType myCtype  = C.GetType();
114
115
116   switch(myCtype) {
117
118   case GeomAbs_Line: 
119     {
120       
121       switch(myStype) {
122       case GeomAbs_Sphere:
123         myExtElCS.Perform(C.Line(), myS->Sphere());
124         break;   
125       case GeomAbs_Cylinder:
126         myExtElCS.Perform(C.Line(), myS->Cylinder());
127         break;
128       case GeomAbs_Plane:
129         myExtElCS.Perform(C.Line(), myS->Plane());
130         if (myExtElCS.IsParallel())   break;
131
132       case GeomAbs_Torus:
133       case GeomAbs_Cone:
134       case GeomAbs_BezierSurface:
135       case GeomAbs_BSplineSurface:
136       case GeomAbs_SurfaceOfRevolution:
137       case GeomAbs_SurfaceOfExtrusion:
138       case GeomAbs_OtherSurface:
139         {
140           Standard_Real cfirst = myucinf, clast = myucsup;
141           Standard_Real ufirst = myS->FirstUParameter(), ulast = myS->LastUParameter(), 
142                         vfirst = myS->FirstVParameter(), vlast = myS->LastVParameter();
143
144           if(Precision::IsInfinite(Abs(cfirst)) || Precision::IsInfinite(Abs(clast))) {
145
146             Bnd_Box aSurfBox;
147       BndLib_AddSurface::Add(*myS, ufirst, ulast, vfirst, vlast, Precision::Confusion(), aSurfBox);
148             Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
149             aSurfBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
150             Standard_Real tmin = Precision::Infinite(), tmax = -tmin;
151             gp_Lin aLin = C.Line();
152             
153
154             if(!( Precision::IsInfinite(Abs(xmin)) || Precision::IsInfinite(Abs(xmax)) || 
155                   Precision::IsInfinite(Abs(ymin)) || Precision::IsInfinite(Abs(ymax)) || 
156                   Precision::IsInfinite(Abs(zmin)) || Precision::IsInfinite(Abs(zmax)))  ) {
157               
158               Extrema_ExtPElC anExt;
159               Extrema_POnCurv aPntOnLin;
160               Standard_Real aParOnLin;
161               Standard_Real lim = Precision::Infinite();
162               gp_Pnt aLimPntArray[8];
163               
164               aLimPntArray[0].SetCoord(xmin, ymin, zmin);
165               aLimPntArray[1].SetCoord(xmax, ymin, zmin);
166               aLimPntArray[2].SetCoord(xmin, ymax, zmin);
167               aLimPntArray[3].SetCoord(xmax, ymax, zmin);
168               aLimPntArray[4].SetCoord(xmin, ymin, zmax);
169               aLimPntArray[5].SetCoord(xmax, ymin, zmax);
170               aLimPntArray[6].SetCoord(xmin, ymax, zmax);
171               aLimPntArray[7].SetCoord(xmax, ymax, zmax);
172
173               for(i = 0; i <= 7; i++) {
174                 anExt.Perform(aLimPntArray[i], aLin, Precision::Confusion(), -lim, lim);
175                 aPntOnLin = anExt.Point(1);
176                 aParOnLin = aPntOnLin.Parameter();
177                 tmin = Min(aParOnLin, tmin);
178                 tmax = Max(aParOnLin, tmax);
179               }
180               
181             }
182             else {
183               tmin = -1.e+50;
184               tmax =  1.e+50;
185             }
186
187
188             cfirst = Max(cfirst, tmin);
189             clast  = Min(clast,  tmax);
190
191           }
192
193
194             
195           Extrema_GenExtCS Ext(C, *myS, NbT, NbU, NbV, cfirst, clast, ufirst, ulast,
196                                vfirst, vlast, mytolC, mytolS);
197
198           myDone = Ext.IsDone();
199           if (myDone) {
200             Standard_Integer NbExt = Ext.NbExt();
201             Standard_Real T,U,V;
202             Extrema_POnCurv PC;
203             Extrema_POnSurf PS;
204             for (i = 1; i <= NbExt; i++) {
205               PC = Ext.PointOnCurve(i);
206               PS = Ext.PointOnSurface(i);
207               T = PC.Parameter();
208               PS.Parameter(U, V);
209               AddSolution(C, T, U, V, PC.Value(), PS.Value(), Ext.SquareDistance(i));
210             }
211           }
212           return;
213           
214         }
215 #ifndef DEB
216       default:
217 #endif
218         break;
219       }
220       break;
221     }
222 //  Modified by skv - Thu Jul  7 12:29:34 2005 OCC9134 Begin
223   case GeomAbs_Circle:
224     {
225       if(myStype == GeomAbs_Cylinder) {
226         myExtElCS.Perform(C.Circle(), myS->Cylinder());
227         break;
228       }
229     }
230   case GeomAbs_Hyperbola: 
231     {
232       if(myCtype == GeomAbs_Hyperbola && myStype == GeomAbs_Plane) {
233 //  Modified by skv - Thu Jul  7 12:29:34 2005 OCC9134 End
234         myExtElCS.Perform(C.Hyperbola(), myS->Plane());
235         break;
236       }
237     }
238   default:
239     {
240       Extrema_GenExtCS Ext;
241       Ext.Initialize(*myS, NbU, NbV, mytolS);
242       if(myCtype == GeomAbs_Hyperbola) {
243         Standard_Real tmin = Max(-20., C.FirstParameter());
244         Standard_Real tmax = Min(20., C.LastParameter());
245         Ext.Perform(C, NbT, tmin, tmax, mytolC); // to avoid overflow
246       }
247       else {
248         if(myCtype == GeomAbs_Circle && NbT < 13) {
249           NbT = 13;
250         }
251         Ext.Perform(C, NbT, mytolC);
252       }
253         
254       myDone = Ext.IsDone();
255       if (myDone) {
256         Standard_Integer NbExt = Ext.NbExt();
257         Standard_Real T,U,V;
258         Extrema_POnCurv PC;
259         Extrema_POnSurf PS;
260         for (i = 1; i <= NbExt; i++) {
261           PC = Ext.PointOnCurve(i);
262           PS = Ext.PointOnSurface(i);
263           T = PC.Parameter();
264           PS.Parameter(U, V);
265           AddSolution(C, T, U, V, PC.Value(), PS.Value(), Ext.SquareDistance(i));
266         }
267
268         //Add sharp points
269         Standard_Integer SolNumber = mySqDist.Length();
270         Standard_Address CopyC = (Standard_Address)&C;
271         Adaptor3d_Curve& aC = *(Adaptor3d_Curve*)CopyC;
272         Standard_Integer NbIntervals = aC.NbIntervals(GeomAbs_C1);
273         TColStd_Array1OfReal SharpPoints(1, NbIntervals+1);
274         aC.Intervals(SharpPoints, GeomAbs_C1);
275         for (i = 1; i <= SharpPoints.Upper(); i++)
276         {
277           T = SharpPoints(i);
278           gp_Pnt aPnt = C.Value(T);
279           Extrema_ExtPS ProjPS(aPnt, *myS, mytolS, mytolS);
280           if (!ProjPS.IsDone())
281             continue;
282           Standard_Integer NbProj = ProjPS.NbExt(), jmin = 0;
283           Standard_Real MinSqDist = RealLast();
284           for (j = 1; j <= NbProj; j++)
285           {
286             Standard_Real aSqDist = ProjPS.SquareDistance(j);
287             if (aSqDist < MinSqDist)
288             {
289               MinSqDist = aSqDist;
290               jmin = j;
291             }
292           }
293           if (jmin != 0)
294           {
295             ProjPS.Point(jmin).Parameter(U,V);
296             AddSolution(C, T, U, V,
297                         aPnt, ProjPS.Point(jmin).Value(), MinSqDist);
298           }
299         }
300         //Cut sharp solutions to keep only minimum and maximum
301         Standard_Integer imin = SolNumber + 1, imax = mySqDist.Length();
302         for (i = SolNumber + 1; i <= mySqDist.Length(); i++)
303         {
304           if (mySqDist(i) < mySqDist(imin))
305             imin = i;
306           if (mySqDist(i) > mySqDist(imax))
307             imax = i;
308         }
309         if (mySqDist.Length() > SolNumber + 2)
310         {
311           Standard_Real MinSqDist = mySqDist(imin);
312           Standard_Real MaxSqDist = mySqDist(imax);
313           Extrema_POnCurv MinPC = myPOnC(imin);
314           Extrema_POnCurv MaxPC = myPOnC(imax);
315           Extrema_POnSurf MinPS = myPOnS(imin);
316           Extrema_POnSurf MaxPS = myPOnS(imax);
317           
318           mySqDist.Remove(SolNumber + 1, mySqDist.Length());
319           myPOnC.Remove(SolNumber + 1, myPOnC.Length());
320           myPOnS.Remove(SolNumber + 1, myPOnS.Length());
321
322           mySqDist.Append(MinSqDist);
323           myPOnC.Append(MinPC);
324           myPOnS.Append(MinPS);
325           mySqDist.Append(MaxSqDist);
326           myPOnC.Append(MaxPC);
327           myPOnS.Append(MaxPS);
328         }
329       }
330       return;
331     }
332     break;
333   }
334   
335   myDone = myExtElCS.IsDone();
336   if (myDone) {
337     myIsPar = myExtElCS.IsParallel();
338     if (myIsPar) {
339       mySqDist.Append(myExtElCS.SquareDistance(1));
340     }
341     else {
342       Standard_Integer NbExt = myExtElCS.NbExt();
343       Standard_Real U, V;
344       for (i = 1; i <= NbExt; i++) {
345         Extrema_POnCurv PC;
346         Extrema_POnSurf PS;
347         myExtElCS.Points(i, PC, PS);
348         Standard_Real Ucurve = PC.Parameter();
349         PS.Parameter(U, V);
350         AddSolution(C, Ucurve, U, V, PC.Value(), PS.Value(), myExtElCS.SquareDistance(i));
351       }
352     }
353   }
354   
355 }
356
357
358 Standard_Boolean Extrema_ExtCS::IsDone() const
359 {
360   return myDone;
361 }
362
363 Standard_Boolean Extrema_ExtCS::IsParallel() const
364 {
365   return myIsPar;
366 }
367
368
369 Standard_Real Extrema_ExtCS::SquareDistance(const Standard_Integer N) const
370 {
371   if(!myDone) StdFail_NotDone::Raise();
372   if (myIsPar && N != 1) StdFail_InfiniteSolutions::Raise();
373   if ((N < 1) || (N > mySqDist.Length())) Standard_OutOfRange::Raise();
374   return mySqDist.Value(N);
375 }
376
377
378 Standard_Integer Extrema_ExtCS::NbExt() const
379 {
380   if(!myDone) StdFail_NotDone::Raise();
381   return mySqDist.Length();
382 }
383
384
385
386 void Extrema_ExtCS::Points(const Standard_Integer N,
387                             Extrema_POnCurv&       P1,
388                             Extrema_POnSurf&       P2) const
389 {
390   if(!myDone) StdFail_NotDone::Raise();
391   P1 = myPOnC.Value(N);
392   P2 = myPOnS.Value(N);
393 }
394
395 Standard_Boolean Extrema_ExtCS::AddSolution(const Adaptor3d_Curve& theCurve,
396                                             const Standard_Real aT,
397                                             const Standard_Real aU,
398                                             const Standard_Real aV,
399                                             const gp_Pnt& PointOnCurve,
400                                             const gp_Pnt& PointOnSurf,
401                                             const Standard_Real SquareDist)
402 {
403   Standard_Boolean Added = Standard_False;
404
405   Standard_Real T = aT, U = aU, V = aV;
406   
407   if (theCurve.IsPeriodic())
408     T = ElCLib::InPeriod(T, myucinf, myucinf + theCurve.Period());
409   if (myS->IsUPeriodic())
410     U = ElCLib::InPeriod(U, myuinf, myuinf + myS->UPeriod());
411   if (myS->IsVPeriodic())
412     V = ElCLib::InPeriod(V, myvinf, myvinf + myS->VPeriod());
413
414   Extrema_POnCurv aPC;
415   Extrema_POnSurf aPS;
416   if ((myucinf-T) <= mytolC && (T-myucsup) <= mytolC &&
417       (myuinf-U) <= mytolS && (U-myusup) <= mytolS &&
418       (myvinf-V) <= mytolS && (V-myvsup) <= mytolS)
419   {
420     Standard_Boolean IsNewSolution = Standard_True;
421     for (Standard_Integer j = 1; j <= mySqDist.Length(); j++)
422     {
423       aPC = myPOnC(j);
424       aPS = myPOnS(j);
425       Standard_Real Tj = aPC.Parameter();
426       Standard_Real Uj, Vj;
427       aPS.Parameter(Uj, Vj);
428       if (Abs(T - Tj) <= mytolC &&
429           Abs(U - Uj) <= mytolS &&
430           Abs(V - Vj) <= mytolS)
431       {
432         IsNewSolution = Standard_False;
433         break;
434       }
435     }
436     if (IsNewSolution)
437     {
438       mySqDist.Append(SquareDist);
439       aPC.SetValues(T, PointOnCurve);
440       myPOnC.Append(aPC);
441       myPOnS.Append(Extrema_POnSurf(U, V, PointOnSurf));
442       Added = Standard_True;
443     }
444   }
445   return Added;
446 }