0023706: Cannot project point on curve
[occt.git] / src / Extrema / Extrema_GExtPC.gxx
1 // Created on: 1992-10-19
2 // Created by: Laurent PAINNOT
3 // Copyright (c) 1992-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 // Modified by cma, Fri Dec 10 18:11:56 1993
22
23 #include Extrema_EPC_hxx
24 #include ThePOnC_hxx
25 #include TheSequenceOfPOnC_hxx
26 #include ThePoint_hxx
27 #include TheVector_hxx
28 #include TheExtPElC_hxx
29 #include <StdFail_NotDone.hxx>
30 #include <Standard_Failure.hxx>
31 #include <GeomAbs_CurveType.hxx>
32 #include <Precision.hxx>
33 #include <ElCLib.hxx>
34 #include <TColStd_Array1OfReal.hxx>
35
36
37 //=======================================================================
38 //function : Perform
39 //purpose  : 
40 //=======================================================================
41
42 void Extrema_GExtPC::Perform(const ThePoint& P)
43 {
44   mySqDist.Clear();
45   mypoint.Clear();
46   myismin.Clear();
47   Standard_Integer i, NbExt, n;                     
48   Standard_Real U;
49   mysample = 17;
50   Standard_Real t3d = Precision::Confusion();
51   if (Precision::IsInfinite(myuinf)) mydist1 = RealLast();
52   else {
53     Pf = TheCurveTool::Value(*((TheCurve*)myC), myuinf);
54     mydist1 = P.SquareDistance(Pf);
55   }
56   
57   if (Precision::IsInfinite(myusup)) mydist2 = RealLast();
58   else {
59     Pl = TheCurveTool::Value(*((TheCurve*)myC), myusup);
60     mydist2 = P.SquareDistance(Pl);
61   }
62
63   switch(type) {
64   case GeomAbs_Circle: 
65     {
66       myExtPElC.Perform(P, TheCurveTool::Circle(*((TheCurve*)myC)), t3d, myuinf, myusup);
67     }
68     break;
69   case GeomAbs_Ellipse: 
70     {
71       myExtPElC.Perform(P, TheCurveTool::Ellipse(*((TheCurve*)myC)), t3d, myuinf, myusup);
72     }
73     break;
74   case GeomAbs_Parabola: 
75     {
76       myExtPElC.Perform(P, TheCurveTool::Parabola(*((TheCurve*)myC)), t3d,myuinf,myusup);
77     }
78     break;
79   case GeomAbs_Hyperbola: 
80     {
81       myExtPElC.Perform(P,TheCurveTool::Hyperbola(*((TheCurve*)myC)),t3d, myuinf, myusup);
82     }
83     break;
84   case GeomAbs_Line: 
85     {
86       myExtPElC.Perform(P, TheCurveTool::Line(*((TheCurve*)myC)), t3d, myuinf, myusup);
87     }
88     break;
89   case GeomAbs_BezierCurve:
90     {
91       myintuinf = myuinf;
92       myintusup = myusup;
93       mysample = (TheCurveTool::Bezier(*((TheCurve*)myC)))->NbPoles()*2;
94       IntervalPerform(P);
95       return;
96     }
97   case GeomAbs_BSplineCurve: 
98     {
99       mysample = (TheCurveTool::BSpline(*((TheCurve*)myC)))->NbPoles()*2;
100     }
101   case GeomAbs_OtherCurve: 
102     {
103       Standard_Boolean IntExtIsDone = Standard_False;
104       Standard_Boolean IntIsNotValid;
105       n = TheCurveTool::NbIntervals(*((TheCurve*)myC), GeomAbs_C2);
106       TColStd_Array1OfReal theInter(1, n+1);
107       Standard_Boolean isPeriodic = TheCurveTool::IsPeriodic(*((TheCurve*)myC));
108       Standard_Real aPeriodicShift = 0.;
109       TheCurveTool::Intervals(*((TheCurve*)myC), theInter, GeomAbs_C2);
110       mysample = Max(mysample/n, 17);
111       TheVector V1;
112       ThePoint PP;
113       Standard_Real s1 = 0.0 ;
114       Standard_Real s2 = 0.0;      
115       for (i = 1; i <= n; i++) {
116         myintuinf = theInter(i);
117         myintusup = theInter(i+1);
118         
119         Standard_Real anInfToCheck = myintuinf;
120         Standard_Real aSupToCheck = myintusup;
121         
122         if (isPeriodic) {
123           Standard_Real aPeriod = TheCurveTool::Period(*((TheCurve*)myC));
124           anInfToCheck = ElCLib::InPeriod(myintuinf, myuinf, myuinf+aPeriod);
125           aSupToCheck = myintusup+(anInfToCheck-myintuinf);
126         }    
127         IntIsNotValid = (myuinf > aSupToCheck) || (myusup < anInfToCheck);
128
129         if(IntIsNotValid) continue;
130
131         if (myuinf >= anInfToCheck) anInfToCheck = myuinf;
132         if (myusup <= aSupToCheck) aSupToCheck = myusup;
133         if((aSupToCheck - anInfToCheck) <= mytolu) continue;
134         
135         if (i != 1)
136           {
137           TheCurveTool::D1(*((TheCurve*)myC), myintuinf, PP, V1);
138           s1 = (TheVector(P, PP))*V1;
139           if (s1*s2 < 0.0) {
140             mySqDist.Append(PP.SquareDistance(P));
141             myismin.Append((s1 < 0.0));
142             mypoint.Append(ThePOnC(myintuinf, PP));
143           }
144         }
145         if (i != n) {
146           TheCurveTool::D1(*((TheCurve*)myC), myintusup, PP, V1);
147           s2 = (TheVector(P, PP))*V1;
148         }
149
150         IntervalPerform(P);
151         IntExtIsDone = IntExtIsDone || mydone;
152       }
153       mydone = IntExtIsDone;
154       return;
155     }
156   }
157   
158   
159   mydone = myExtPElC.IsDone();
160   if (mydone) {
161     NbExt = myExtPElC.NbExt();
162     for (i = 1; i <= NbExt; i++) {
163       // Verification de la validite des parametres:
164       ThePOnC PC = myExtPElC.Point(i);
165       U = PC.Parameter();
166       if (TheCurveTool::IsPeriodic(*((TheCurve*)myC))) {
167             U = ElCLib::InPeriod(U, myuinf, myuinf+TheCurveTool::Period(*((TheCurve*)myC)));
168       }
169       if ((U >= myuinf-mytolu) && (U <= myusup+mytolu)){
170         PC.SetValues(U, myExtPElC.Point(i).Value());
171         mySqDist.Append(myExtPElC.SquareDistance(i));
172         myismin.Append(myExtPElC.IsMin(i));
173         mypoint.Append(PC);
174       }
175     }
176   } 
177 }
178
179
180 //=======================================================================
181 //function : Initialize
182 //purpose  : 
183 //=======================================================================
184
185 void Extrema_GExtPC::Initialize(const TheCurve&     C,
186                                 const Standard_Real Uinf,
187                                 const Standard_Real Usup,
188                                 const Standard_Real TolF) 
189 {
190   myC = (Standard_Address)&C;
191   myintuinf = myuinf = Uinf;
192   myintusup = myusup = Usup;
193   mytolf = TolF;
194   mytolu = TheCurveTool::Resolution(*((TheCurve*)myC), Precision::Confusion());
195   type = TheCurveTool::GetType(C);
196   mydone = Standard_False;
197   mydist1 = RealLast();
198   mydist2 = RealLast();
199   mysample = 17;
200 }
201
202
203 //=======================================================================
204 //function : IntervalPerform
205 //purpose  : 
206 //=======================================================================
207
208 void Extrema_GExtPC::IntervalPerform(const ThePoint& P)
209 {
210   Standard_Integer i;
211   Standard_Real U;
212   myExtPC.Initialize((*((TheCurve*)myC)), mysample, 
213                      myintuinf, myintusup, mytolu, mytolf);
214   myExtPC.Perform(P);
215   mydone = myExtPC.IsDone();
216   if (mydone) {
217     Standard_Integer NbExt = myExtPC.NbExt();
218     for (i = 1; i <= NbExt; i++) {
219       // Verification de la validite des parametres pour le cas trimme:
220       ThePOnC PC = myExtPC.Point(i);
221       U = PC.Parameter();
222       if (TheCurveTool::IsPeriodic(*((TheCurve*)myC))) {
223         U = ElCLib::InPeriod(U, myuinf, myuinf+TheCurveTool::Period(*((TheCurve*)myC)));
224       }
225       if ((U >= myuinf - mytolu) && (U <= myusup + mytolu)) {
226         PC.SetValues(U, PC.Value());
227         mySqDist.Append(myExtPC.SquareDistance(i));
228         myismin.Append(myExtPC.IsMin(i));
229         mypoint.Append(PC);
230       }
231     }
232   }
233 }
234
235
236
237
238 //=======================================================================
239 //function : Extrema_GExtPC
240 //purpose  : 
241 //=======================================================================
242
243 Extrema_GExtPC::Extrema_GExtPC()
244 {
245   myC = 0;
246   mydone = Standard_False;
247   mydist1 = RealLast();
248   mydist2 = RealLast();
249   mytolu = 0.0;
250   mytolf = 0.0;
251   mysample = 17;
252   myintuinf = myintusup = myuinf = myusup = Precision::Infinite();
253   type = GeomAbs_OtherCurve;
254 }
255
256 //=======================================================================
257 //function : Extrema_GExtPC
258 //purpose  : 
259 //=======================================================================
260
261 Extrema_GExtPC::Extrema_GExtPC(const ThePoint&           P, 
262                                const TheCurve&           C,
263                                const Standard_Real       Uinf,
264                                const Standard_Real       Usup,
265                                const Standard_Real       TolF) 
266 {
267   Initialize(C, Uinf, Usup, TolF);
268   Perform(P);
269 }
270
271 //=======================================================================
272 //function : Extrema_GExtPC
273 //purpose  : 
274 //=======================================================================
275
276 Extrema_GExtPC::Extrema_GExtPC(const ThePoint&     P, 
277                                const TheCurve&     C,
278                                const Standard_Real TolF) 
279 {
280   Initialize(C, TheCurveTool::FirstParameter(C), 
281              TheCurveTool::LastParameter(C), TolF);
282   Perform(P);
283 }
284
285
286 //=======================================================================
287 //function : IsDone
288 //purpose  : 
289 //=======================================================================
290
291 Standard_Boolean Extrema_GExtPC::IsDone() const
292 {
293   return mydone;
294 }
295
296
297 //=======================================================================
298 //function : Value
299 //purpose  : 
300 //=======================================================================
301
302 Standard_Real Extrema_GExtPC::SquareDistance(const Standard_Integer N) const 
303 {
304   if(!mydone) StdFail_NotDone::Raise();
305   if ((N < 1) || (N > mySqDist.Length())) Standard_OutOfRange::Raise();
306   return mySqDist.Value(N);
307 }
308
309
310 //=======================================================================
311 //function : NbExt
312 //purpose  : 
313 //=======================================================================
314
315 Standard_Integer Extrema_GExtPC::NbExt() const
316 {
317   if(!mydone) StdFail_NotDone::Raise();
318   return mySqDist.Length();
319 }
320
321
322 //=======================================================================
323 //function : IsMin
324 //purpose  : 
325 //=======================================================================
326
327 Standard_Boolean Extrema_GExtPC::IsMin(const Standard_Integer N) const
328 {
329   if(!mydone) StdFail_NotDone::Raise();
330   if ((N < 1) || (N > mySqDist.Length())) Standard_OutOfRange::Raise();
331   return myismin.Value(N);
332 }
333
334
335
336 //=======================================================================
337 //function : Point
338 //purpose  : 
339 //=======================================================================
340
341 ThePOnC Extrema_GExtPC::Point(const Standard_Integer N) const
342 {
343   if(!mydone) StdFail_NotDone::Raise();
344   if ((N < 1) || (N > mySqDist.Length())) Standard_OutOfRange::Raise();
345   return mypoint.Value(N);
346 }
347
348
349 //=======================================================================
350 //function : TrimmedDistances
351 //purpose  : 
352 //=======================================================================
353
354 void Extrema_GExtPC::TrimmedSquareDistances(Standard_Real& dist1, 
355                                       Standard_Real& dist2,
356                                       ThePoint& P1,
357                                       ThePoint& P2) const
358 {
359   dist1 = mydist1;
360   dist2 = mydist2;
361   P1 = Pf;
362   P2 = Pl;
363 }
364