0029712: Extrema algorithm raises exception
[occt.git] / src / Extrema / Extrema_ExtCS.cxx
CommitLineData
b311480e 1// Created on: 1995-07-18
2// Created by: Modelistation
3// Copyright (c) 1995-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
17// Modified by skv - Thu Jul 7 12:29:34 2005 OCC9134
18
42cf5bc1 19#include <Adaptor3d_Curve.hxx>
20#include <Adaptor3d_Surface.hxx>
21#include <Bnd_Box.hxx>
22#include <BndLib_AddSurface.hxx>
23#include <ElCLib.hxx>
24#include <ElSLib.hxx>
25#include <Extrema_ExtCS.hxx>
42cf5bc1 26#include <Extrema_ExtPS.hxx>
7fd59977 27#include <Extrema_GenExtCS.hxx>
42cf5bc1 28#include <Extrema_POnCurv.hxx>
29#include <Extrema_POnSurf.hxx>
7fd59977 30#include <GeomAbs_CurveType.hxx>
7fd59977 31#include <gp_Cone.hxx>
42cf5bc1 32#include <gp_Cylinder.hxx>
33#include <gp_Lin.hxx>
34#include <gp_Pln.hxx>
35#include <gp_Pnt.hxx>
7fd59977 36#include <gp_Sphere.hxx>
37#include <gp_Torus.hxx>
42cf5bc1 38#include <Precision.hxx>
39#include <Standard_NotImplemented.hxx>
40#include <Standard_OutOfRange.hxx>
41#include <Standard_TypeMismatch.hxx>
42#include <StdFail_InfiniteSolutions.hxx>
43#include <StdFail_NotDone.hxx>
38308958 44#include <TColStd_Array1OfReal.hxx>
7fd59977 45
46Extrema_ExtCS::Extrema_ExtCS()
47{
48 myDone = Standard_False;
49}
50
51Extrema_ExtCS::Extrema_ExtCS(const Adaptor3d_Curve& C,
29d778bf 52 const Adaptor3d_Surface& S,
53 const Standard_Real TolC,
54 const Standard_Real TolS)
7fd59977 55
56{
57 Initialize(S, S.FirstUParameter(), S.LastUParameter(),
29d778bf 58 S.FirstVParameter(), S.LastVParameter(),
59 TolC, TolS);
7fd59977 60 Perform(C, C.FirstParameter(), C.LastParameter());
61}
62
63Extrema_ExtCS::Extrema_ExtCS(const Adaptor3d_Curve& C,
29d778bf 64 const Adaptor3d_Surface& S,
65 const Standard_Real UCinf,
66 const Standard_Real UCsup,
67 const Standard_Real Uinf,
68 const Standard_Real Usup,
69 const Standard_Real Vinf,
70 const Standard_Real Vsup,
71 const Standard_Real TolC,
72 const Standard_Real TolS)
7fd59977 73
74{
75 Initialize(S, Uinf, Usup, Vinf, Vsup, TolC, TolS);
76 Perform(C, UCinf, UCsup);
77}
78
79
80void Extrema_ExtCS::Initialize(const Adaptor3d_Surface& S,
29d778bf 81 const Standard_Real Uinf,
82 const Standard_Real Usup,
83 const Standard_Real Vinf,
84 const Standard_Real Vsup,
85 const Standard_Real TolC,
86 const Standard_Real TolS)
7fd59977 87{
88 myS = (Adaptor3d_SurfacePtr)&S;
89 myIsPar = Standard_False;
90 myuinf = Uinf;
91 myusup = Usup;
92 myvinf = Vinf;
93 myvsup = Vsup;
94 mytolC = TolC;
95 mytolS = TolS;
96 myStype = myS->GetType();
97}
98
29d778bf 99
7fd59977 100void Extrema_ExtCS::Perform(const Adaptor3d_Curve& C,
29d778bf 101 const Standard_Real Uinf,
102 const Standard_Real Usup)
7fd59977 103{
104 myucinf = Uinf;
105 myucsup = Usup;
106 myPOnS.Clear();
107 myPOnC.Clear();
108 mySqDist.Clear();
38308958 109 Standard_Integer i, j;
7fd59977 110 Standard_Integer NbT, NbU, NbV;
111 NbT = NbU = NbV = 10;
112 GeomAbs_CurveType myCtype = C.GetType();
113
03cca6f7 114 myDone = Standard_False;
115 // Try analytic computation of extrema
116 Standard_Boolean isComputeAnalytic = Standard_True;
7fd59977 117
118 switch(myCtype) {
119
120 case GeomAbs_Line:
121 {
29d778bf 122
7fd59977 123 switch(myStype) {
124 case GeomAbs_Sphere:
29d778bf 125 myExtElCS.Perform(C.Line(), myS->Sphere());
126 break;
7fd59977 127 case GeomAbs_Cylinder:
29d778bf 128 myExtElCS.Perform(C.Line(), myS->Cylinder());
129 break;
7fd59977 130 case GeomAbs_Plane:
29d778bf 131 myExtElCS.Perform(C.Line(), myS->Plane());
132 if (myExtElCS.IsParallel()) break;
b1811c1d 133 Standard_FALLTHROUGH
7fd59977 134
135 case GeomAbs_Torus:
136 case GeomAbs_Cone:
137 case GeomAbs_BezierSurface:
138 case GeomAbs_BSplineSurface:
139 case GeomAbs_SurfaceOfRevolution:
140 case GeomAbs_SurfaceOfExtrusion:
1896126e 141 case GeomAbs_OffsetSurface:
7fd59977 142 case GeomAbs_OtherSurface:
29d778bf 143 {
144 Standard_Real cfirst = myucinf, clast = myucsup;
145 Standard_Real ufirst = myS->FirstUParameter(), ulast = myS->LastUParameter(),
146 vfirst = myS->FirstVParameter(), vlast = myS->LastVParameter();
7fd59977 147
4563cf3e 148 if (!(Precision::IsInfinite(ufirst) || Precision::IsInfinite(ulast) ||
149 Precision::IsInfinite(vfirst) || Precision::IsInfinite(vlast)))
150 {
151 Standard_Real tmin = Precision::Infinite(), tmax = -tmin;
152 Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
29d778bf 153 Bnd_Box aSurfBox;
1896126e 154 BndLib_AddSurface::Add(*myS, ufirst, ulast, vfirst, vlast, Precision::Confusion(), aSurfBox);
29d778bf 155 aSurfBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
29d778bf 156 gp_Lin aLin = C.Line();
4563cf3e 157 Standard_Real aParOnLin;
158 gp_Pnt aLimPntArray[8];
159
160 aLimPntArray[0].SetCoord(xmin, ymin, zmin);
161 aLimPntArray[1].SetCoord(xmax, ymin, zmin);
162 aLimPntArray[2].SetCoord(xmin, ymax, zmin);
163 aLimPntArray[3].SetCoord(xmax, ymax, zmin);
164 aLimPntArray[4].SetCoord(xmin, ymin, zmax);
165 aLimPntArray[5].SetCoord(xmax, ymin, zmax);
166 aLimPntArray[6].SetCoord(xmin, ymax, zmax);
167 aLimPntArray[7].SetCoord(xmax, ymax, zmax);
168
169 for (i = 0; i <= 7; i++) {
170 aParOnLin = ElCLib::Parameter(aLin, aLimPntArray[i]);
171 tmin = Min(aParOnLin, tmin);
172 tmax = Max(aParOnLin, tmax);
29d778bf 173 }
29d778bf 174 cfirst = Max(cfirst, tmin);
4563cf3e 175 clast = Min(clast, tmax);
29d778bf 176 }
177
fa6d1712 178 if (myS->IsUPeriodic())
179 NbU = 13;
180 if (myS->IsVPeriodic())
181 NbV = 13;
29d778bf 182
183 Extrema_GenExtCS Ext(C, *myS, NbT, NbU, NbV, cfirst, clast, ufirst, ulast,
184 vfirst, vlast, mytolC, mytolS);
185
186 myDone = Ext.IsDone();
187 if (myDone) {
188 Standard_Integer NbExt = Ext.NbExt();
189 Standard_Real T,U,V;
190 Extrema_POnCurv PC;
191 Extrema_POnSurf PS;
192 for (i = 1; i <= NbExt; i++) {
193 PC = Ext.PointOnCurve(i);
194 PS = Ext.PointOnSurface(i);
195 T = PC.Parameter();
196 PS.Parameter(U, V);
38308958 197 AddSolution(C, T, U, V, PC.Value(), PS.Value(), Ext.SquareDistance(i));
29d778bf 198 }
199 }
200 return;
29d778bf 201 }
7fd59977 202 }
203 break;
204 }
29d778bf 205 // Modified by skv - Thu Jul 7 12:29:34 2005 OCC9134 Begin
7fd59977 206 case GeomAbs_Circle:
207 {
208 if(myStype == GeomAbs_Cylinder) {
29d778bf 209 myExtElCS.Perform(C.Circle(), myS->Cylinder());
210 break;
7fd59977 211 }
9dfbbfe6 212 else if(myStype == GeomAbs_Plane)
213 {
214 myExtElCS.Perform(C.Circle(), myS->Plane());
215 break;
216 }
03cca6f7 217 else if (myStype == GeomAbs_Sphere)
218 {
219 myExtElCS.Perform(C.Circle(), myS->Sphere());
220 break;
221 }
7fd59977 222 }
b1811c1d 223 Standard_FALLTHROUGH
7fd59977 224 case GeomAbs_Hyperbola:
225 {
226 if(myCtype == GeomAbs_Hyperbola && myStype == GeomAbs_Plane) {
29d778bf 227 // Modified by skv - Thu Jul 7 12:29:34 2005 OCC9134 End
228 myExtElCS.Perform(C.Hyperbola(), myS->Plane());
229 break;
7fd59977 230 }
231 }
b1811c1d 232 Standard_FALLTHROUGH
7fd59977 233 default:
234 {
03cca6f7 235 isComputeAnalytic = Standard_False;
236 break;
237 }
238 }
239
240 if (isComputeAnalytic)
241 {
242 if (myExtElCS.IsDone())
243 {
244 myDone = Standard_True;
245 myIsPar = myExtElCS.IsParallel();
246 if (myIsPar)
247 {
248 mySqDist.Append(myExtElCS.SquareDistance(1));
7fd59977 249 }
03cca6f7 250 else
251 {
252 Standard_Integer NbExt = myExtElCS.NbExt();
253 for (i = 1; i <= NbExt; i++)
fa6d1712 254 {
03cca6f7 255 Extrema_POnCurv PC;
256 Extrema_POnSurf PS;
257 myExtElCS.Points(i, PC, PS);
258 Standard_Real Ucurve = PC.Parameter();
259 Standard_Real U, V;
29d778bf 260 PS.Parameter(U, V);
03cca6f7 261 AddSolution(C, Ucurve, U, V, PC.Value(), PS.Value(), myExtElCS.SquareDistance(i));
29d778bf 262 }
38308958 263
03cca6f7 264 if (mySqDist.Length() == 0 && NbExt > 0)
38308958 265 {
03cca6f7 266 // Analytical extrema seem to be out of curve/surface boundaries.
267 // Try extremity points of curve.
268 gp_Pnt aPOnC[2], aPOnS[2];
269 Standard_Real aT[2] = { myucinf, myucsup }, U[2], V[2];
270 Standard_Real aDist[2] = { -1, -1 };
271 for (i = 0; i < 2; ++i)
38308958 272 {
03cca6f7 273 if (Precision::IsInfinite(aT[i]))
274 continue;
275
276 aPOnC[i] = C.Value(aT[i]);
277 switch (myStype)
38308958 278 {
03cca6f7 279 case GeomAbs_Plane:
280 {
281 ElSLib::Parameters(myS->Plane(), aPOnC[i], U[i], V[i]);
282 aPOnS[i] = ElSLib::Value(U[i], V[i], myS->Plane());
283 break;
284 }
285 case GeomAbs_Sphere:
286 {
287 ElSLib::Parameters(myS->Sphere(), aPOnC[i], U[i], V[i]);
288 aPOnS[i] = ElSLib::Value(U[i], V[i], myS->Sphere());
289 break;
290 }
291 case GeomAbs_Cylinder:
292 {
293 ElSLib::Parameters(myS->Cylinder(), aPOnC[i], U[i], V[i]);
294 aPOnS[i] = ElSLib::Value(U[i], V[i], myS->Cylinder());
295 break;
296 }
297 case GeomAbs_Torus:
298 {
299 ElSLib::Parameters(myS->Torus(), aPOnC[i], U[i], V[i]);
300 aPOnS[i] = ElSLib::Value(U[i], V[i], myS->Torus());
301 break;
302 }
303 case GeomAbs_Cone:
304 {
305 ElSLib::Parameters(myS->Cone(), aPOnC[i], U[i], V[i]);
306 aPOnS[i] = ElSLib::Value(U[i], V[i], myS->Cone());
307 break;
308 }
309 default:
310 continue;
38308958 311 }
03cca6f7 312
313 aDist[i] = aPOnC[i].SquareDistance(aPOnS[i]);
38308958 314 }
03cca6f7 315
316 Standard_Boolean bAdd[2] = {Standard_False, Standard_False};
317
318 // Choose solution to add
319 if (aDist[0] >= 0. && aDist[1] >= 0.)
38308958 320 {
03cca6f7 321 Standard_Real aDiff = aDist[0] - aDist[1];
322 // Both computed -> take only minimal
323 if (Abs(aDiff) < Precision::Confusion())
324 // Add both
325 bAdd[0] = bAdd[1] = Standard_True;
326 else if (aDiff < 0)
327 // Add first
328 bAdd[0] = Standard_True;
329 else
330 // Add second
331 bAdd[1] = Standard_True;
332 }
333 else if (aDist[0] >= 0.)
334 // Add first
335 bAdd[0] = Standard_True;
336 else if (aDist[1] >= 0.)
337 // Add second
338 bAdd[1] = Standard_True;
339
340 for (i = 0; i < 2; ++i)
341 {
342 if (bAdd[i])
343 AddSolution(C, aT[i], U[i], V[i], aPOnC[i], aPOnS[i], aDist[i]);
38308958 344 }
38308958 345 }
7fd59977 346 }
347 return;
348 }
7fd59977 349 }
29d778bf 350
03cca6f7 351 // Elementary extrema is not done, try generic solution
352 Extrema_GenExtCS Ext;
353 Ext.Initialize(*myS, NbU, NbV, mytolS);
354 if (myCtype == GeomAbs_Hyperbola) {
355 Standard_Real tmin = Max(-20., C.FirstParameter());
356 Standard_Real tmax = Min(20., C.LastParameter());
357 Ext.Perform(C, NbT, tmin, tmax, mytolC); // to avoid overflow
358 }
359 else {
360 if ((myCtype == GeomAbs_Circle && NbT < 13) ||
361 (myCtype == GeomAbs_BSplineCurve && NbT < 13))
362 {
363 NbT = 13;
364 }
365 Ext.Perform(C, NbT, mytolC);
366 }
367
368 myDone = Ext.IsDone();
7fd59977 369 if (myDone) {
03cca6f7 370 Standard_Integer NbExt = Ext.NbExt();
371 Standard_Real T, U, V;
372 Extrema_POnCurv PC;
373 Extrema_POnSurf PS;
374 for (i = 1; i <= NbExt; i++) {
375 PC = Ext.PointOnCurve(i);
376 PS = Ext.PointOnSurface(i);
377 T = PC.Parameter();
378 PS.Parameter(U, V);
379 AddSolution(C, T, U, V, PC.Value(), PS.Value(), Ext.SquareDistance(i));
7fd59977 380 }
03cca6f7 381
382 //Add sharp points
383 Standard_Integer SolNumber = mySqDist.Length();
384 Standard_Address CopyC = (Standard_Address)&C;
385 Adaptor3d_Curve& aC = *(Adaptor3d_Curve*)CopyC;
386 Standard_Integer NbIntervals = aC.NbIntervals(GeomAbs_C1);
387 TColStd_Array1OfReal SharpPoints(1, NbIntervals + 1);
388 aC.Intervals(SharpPoints, GeomAbs_C1);
389
390 Extrema_ExtPS aProjPS;
391 aProjPS.Initialize(*myS,
392 myS->FirstUParameter(),
393 myS->LastUParameter(),
394 myS->FirstVParameter(),
395 myS->LastVParameter(),
396 mytolS,
397 mytolS);
398
399 for (i = 2; i < SharpPoints.Upper(); ++i)
400 {
401 T = SharpPoints(i);
402 gp_Pnt aPnt = C.Value(T);
403 aProjPS.Perform(aPnt);
404 if (!aProjPS.IsDone())
405 continue;
406 Standard_Integer NbProj = aProjPS.NbExt(), jmin = 0;
407 Standard_Real MinSqDist = RealLast();
408 for (j = 1; j <= NbProj; j++)
9dfbbfe6 409 {
03cca6f7 410 Standard_Real aSqDist = aProjPS.SquareDistance(j);
411 if (aSqDist < MinSqDist)
9dfbbfe6 412 {
03cca6f7 413 MinSqDist = aSqDist;
414 jmin = j;
9dfbbfe6 415 }
416 }
03cca6f7 417 if (jmin != 0)
418 {
419 aProjPS.Point(jmin).Parameter(U, V);
420 AddSolution(C, T, U, V,
421 aPnt, aProjPS.Point(jmin).Value(), MinSqDist);
422 }
423 }
424 //Cut sharp solutions to keep only minimum and maximum
425 Standard_Integer imin = SolNumber + 1, imax = mySqDist.Length();
426 for (i = SolNumber + 1; i <= mySqDist.Length(); i++)
427 {
428 if (mySqDist(i) < mySqDist(imin))
429 imin = i;
430 if (mySqDist(i) > mySqDist(imax))
431 imax = i;
432 }
433 if (mySqDist.Length() > SolNumber + 2)
434 {
435 Standard_Real MinSqDist = mySqDist(imin);
436 Standard_Real MaxSqDist = mySqDist(imax);
437 Extrema_POnCurv MinPC = myPOnC(imin);
438 Extrema_POnCurv MaxPC = myPOnC(imax);
439 Extrema_POnSurf MinPS = myPOnS(imin);
440 Extrema_POnSurf MaxPS = myPOnS(imax);
441
442 mySqDist.Remove(SolNumber + 1, mySqDist.Length());
443 myPOnC.Remove(SolNumber + 1, myPOnC.Length());
444 myPOnS.Remove(SolNumber + 1, myPOnS.Length());
445
446 mySqDist.Append(MinSqDist);
447 myPOnC.Append(MinPC);
448 myPOnS.Append(MinPS);
449 mySqDist.Append(MaxSqDist);
450 myPOnC.Append(MaxPC);
451 myPOnS.Append(MaxPS);
7fd59977 452 }
453 }
7fd59977 454}
455
456
457Standard_Boolean Extrema_ExtCS::IsDone() const
458{
459 return myDone;
460}
461
462Standard_Boolean Extrema_ExtCS::IsParallel() const
463{
638ad7f3 464 if (!IsDone())
465 {
466 throw StdFail_NotDone();
467 }
468
7fd59977 469 return myIsPar;
470}
471
472
473Standard_Real Extrema_ExtCS::SquareDistance(const Standard_Integer N) const
474{
638ad7f3 475 if (N < 1 || N > NbExt())
476 {
477 throw Standard_OutOfRange();
478 }
479
7fd59977 480 return mySqDist.Value(N);
481}
482
483
484Standard_Integer Extrema_ExtCS::NbExt() const
485{
638ad7f3 486 if (!IsDone())
487 {
488 throw StdFail_NotDone();
489 }
490
491 return mySqDist.Length();
7fd59977 492}
493
494
495
496void Extrema_ExtCS::Points(const Standard_Integer N,
638ad7f3 497 Extrema_POnCurv& P1,
498 Extrema_POnSurf& P2) const
7fd59977 499{
638ad7f3 500 if (IsParallel())
501 {
502 throw StdFail_InfiniteSolutions();
503 }
504
505 if (N < 1 || N > NbExt())
506 {
507 throw Standard_OutOfRange();
508 }
509
7fd59977 510 P1 = myPOnC.Value(N);
511 P2 = myPOnS.Value(N);
512}
38308958 513
514Standard_Boolean Extrema_ExtCS::AddSolution(const Adaptor3d_Curve& theCurve,
29d778bf 515 const Standard_Real aT,
516 const Standard_Real aU,
517 const Standard_Real aV,
518 const gp_Pnt& PointOnCurve,
519 const gp_Pnt& PointOnSurf,
520 const Standard_Real SquareDist)
38308958 521{
522 Standard_Boolean Added = Standard_False;
523
524 Standard_Real T = aT, U = aU, V = aV;
29d778bf 525
38308958 526 if (theCurve.IsPeriodic())
527 T = ElCLib::InPeriod(T, myucinf, myucinf + theCurve.Period());
528 if (myS->IsUPeriodic())
529 U = ElCLib::InPeriod(U, myuinf, myuinf + myS->UPeriod());
530 if (myS->IsVPeriodic())
531 V = ElCLib::InPeriod(V, myvinf, myvinf + myS->VPeriod());
532
533 Extrema_POnCurv aPC;
534 Extrema_POnSurf aPS;
535 if ((myucinf-T) <= mytolC && (T-myucsup) <= mytolC &&
29d778bf 536 (myuinf-U) <= mytolS && (U-myusup) <= mytolS &&
537 (myvinf-V) <= mytolS && (V-myvsup) <= mytolS)
38308958 538 {
539 Standard_Boolean IsNewSolution = Standard_True;
540 for (Standard_Integer j = 1; j <= mySqDist.Length(); j++)
541 {
542 aPC = myPOnC(j);
543 aPS = myPOnS(j);
544 Standard_Real Tj = aPC.Parameter();
545 Standard_Real Uj, Vj;
546 aPS.Parameter(Uj, Vj);
547 if (Abs(T - Tj) <= mytolC &&
29d778bf 548 Abs(U - Uj) <= mytolS &&
549 Abs(V - Vj) <= mytolS)
38308958 550 {
551 IsNewSolution = Standard_False;
552 break;
553 }
554 }
555 if (IsNewSolution)
556 {
557 mySqDist.Append(SquareDist);
558 aPC.SetValues(T, PointOnCurve);
559 myPOnC.Append(aPC);
560 myPOnS.Append(Extrema_POnSurf(U, V, PointOnSurf));
561 Added = Standard_True;
562 }
563 }
564 return Added;
565}