0023863: Wrong distance value between circle and cylinder
[occt.git] / src / Extrema / Extrema_GenExtPS.cxx
CommitLineData
b311480e 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
7fd59977 21
22// Modified by skv - Thu Sep 30 15:21:07 2004 OCC593
23
24
25#include <Extrema_GenExtPS.ixx>
26#include <StdFail_NotDone.hxx>
27#include <Standard_OutOfRange.hxx>
28#include <TColStd_Array2OfInteger.hxx>
29#include <TColStd_Array2OfReal.hxx>
30#include <TColgp_Array2OfPnt.hxx>
31#include <math_FunctionSetRoot.hxx>
32#include <math_Vector.hxx>
33#include <math_NewtonFunctionSetRoot.hxx>
34#include <GeomAbs_IsoType.hxx>
92d1589b
A
35#include <Bnd_Sphere.hxx>
36#include <Extrema_HUBTreeOfSphere.hxx>
37#include <Extrema_ExtFlag.hxx>
38#include <Bnd_Array1OfSphere.hxx>
39#include <Bnd_HArray1OfSphere.hxx>
5368adff 40#include <Precision.hxx>
41#include <Geom_OffsetSurface.hxx>
42#include <Geom_RectangularTrimmedSurface.hxx>
43#include <Geom_BSplineSurface.hxx>
44#include <Geom_BezierSurface.hxx>
45#include <Adaptor3d_HSurface.hxx>
46#include <Adaptor3d_HCurve.hxx>
47#include <Adaptor3d_Curve.hxx>
48#include <Geom_BSplineCurve.hxx>
49#include <Geom_BezierCurve.hxx>
92d1589b
A
50//IMPLEMENT_HARRAY1(Extrema_HArray1OfSphere)
51
52
53class Bnd_SphereUBTreeSelector : public Extrema_UBTreeOfSphere::Selector
54{
55 public:
56
57 Bnd_SphereUBTreeSelector (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
58Bnd_Sphere& theSol)
59 : myXYZ(0,0,0),
60 mySphereArray(theSphereArray),
61 mySol(theSol)
62 {
92d1589b
A
63 }
64
65 void DefineCheckPoint( const gp_Pnt& theXYZ )
66 { myXYZ = theXYZ; }
67
68 Bnd_Sphere& Sphere() const
69 { return mySol; }
70
71 virtual Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const = 0;
72
73 virtual Standard_Boolean Accept(const Standard_Integer& theObj) = 0;
92d1589b 74 protected:
d390b166 75 gp_Pnt myXYZ;
76 const Handle(Bnd_HArray1OfSphere)& mySphereArray;
77 Bnd_Sphere& mySol;
78 private:
79 void operator= (const Bnd_SphereUBTreeSelector&);
92d1589b
A
80
81};
82
83class Bnd_SphereUBTreeSelectorMin : public Bnd_SphereUBTreeSelector
84{
85public:
86 Bnd_SphereUBTreeSelectorMin (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
87 Bnd_Sphere& theSol)
88 : Bnd_SphereUBTreeSelector(theSphereArray, theSol),
89 myMinDist(RealLast())
90 {}
91
92 void SetMinDist( const Standard_Real theMinDist )
93 { myMinDist = theMinDist; }
94
95 Standard_Real MinDist() const
96 { return myMinDist; }
97
98 Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const
99 {
100 Bnd_SphereUBTreeSelectorMin* me =
101 const_cast<Bnd_SphereUBTreeSelectorMin*>(this);
102 // myMinDist is decreased each time a nearer object is found
103 return theBnd.IsOut( myXYZ.XYZ(), me->myMinDist );
104 }
105
106 Standard_Boolean Accept(const Standard_Integer&);
107
108private:
109 Standard_Real myMinDist;
110};
111
112Standard_Boolean Bnd_SphereUBTreeSelectorMin::Accept(const Standard_Integer& theInd)
113{
114 const Bnd_Sphere& aSph = mySphereArray->Value(theInd);
115 Standard_Real aCurDist;
116
117 if ( (aCurDist = aSph.SquareDistance(myXYZ.XYZ())) < mySol.SquareDistance(myXYZ.XYZ()) )
118 {
119 mySol = aSph;
120 if ( aCurDist < myMinDist )
121 myMinDist = aCurDist;
122
123 return Standard_True;
124 }
125
126 return Standard_False;
127}
128
129class Bnd_SphereUBTreeSelectorMax : public Bnd_SphereUBTreeSelector
130{
131public:
132 Bnd_SphereUBTreeSelectorMax (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
133 Bnd_Sphere& theSol)
134 : Bnd_SphereUBTreeSelector(theSphereArray, theSol),
135 myMaxDist(0)
136 {}
137
138 void SetMaxDist( const Standard_Real theMaxDist )
139 { myMaxDist = theMaxDist; }
140
141 Standard_Real MaxDist() const
142 { return myMaxDist; }
143
144 Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const
145 {
146 Bnd_SphereUBTreeSelectorMax* me =
147 const_cast<Bnd_SphereUBTreeSelectorMax*>(this);
148 // myMaxDist is decreased each time a nearer object is found
149 return theBnd.IsOut( myXYZ.XYZ(), me->myMaxDist );
150 }
151
152 Standard_Boolean Accept(const Standard_Integer&);
153
154private:
155 Standard_Real myMaxDist;
156};
157
158Standard_Boolean Bnd_SphereUBTreeSelectorMax::Accept(const Standard_Integer& theInd)
159{
160 const Bnd_Sphere& aSph = mySphereArray->Value(theInd);
161 Standard_Real aCurDist;
162
163 if ( (aCurDist = aSph.SquareDistance(myXYZ.XYZ())) > mySol.SquareDistance(myXYZ.XYZ()) )
164 {
165 mySol = aSph;
166 if ( aCurDist > myMaxDist )
167 myMaxDist = aCurDist;
168
169 return Standard_True;
170 }
171
172 return Standard_False;
173}
7fd59977 174
6060dd1f 175/*
176 * This function computes the point on surface parameters on edge.
177 * if it coincides with theParam0 or theParam1, it is returned.
178 */
179static Extrema_POnSurfParams ComputeEdgeParameters
180 (const Standard_Boolean IsUEdge,
181 const Extrema_POnSurfParams &theParam0,
182 const Extrema_POnSurfParams &theParam1,
183 const Adaptor3d_SurfacePtr &theSurf,
184 const gp_Pnt &thePoint,
185 const Standard_Real theDiffTol)
186{
187 const Standard_Real aSqrDist01 =
188 theParam0.Value().SquareDistance(theParam1.Value());
189
190 if (aSqrDist01 <= theDiffTol) {
191 // The points are confused. Get the first point and change its type.
192 return theParam0;
193 } else {
194 const Standard_Real aDiffDist =
195 Abs(theParam0.GetSqrDistance() - theParam1.GetSqrDistance());
196
197 if (aDiffDist >= aSqrDist01 - theDiffTol) {
198 // The shortest distance is one of the nodes.
199 if (theParam0.GetSqrDistance() > theParam1.GetSqrDistance()) {
200 // The shortest distance is the point 1.
201 return theParam1;
202 } else {
203 // The shortest distance is the point 0.
204 return theParam0;
205 }
206 } else {
207 // The shortest distance is inside the edge.
208 gp_XYZ aPoP(thePoint.XYZ().Subtracted(theParam0.Value().XYZ()));
209 gp_XYZ aPoP1(theParam1.Value().XYZ().Subtracted(theParam0.Value().XYZ()));
210 Standard_Real aRatio = aPoP.Dot(aPoP1)/aSqrDist01;
211 Standard_Real aU[2];
212 Standard_Real aV[2];
213
214 theParam0.Parameter(aU[0], aV[0]);
215 theParam1.Parameter(aU[1], aV[1]);
216
217 Standard_Real aUPar = aU[0];
218 Standard_Real aVPar = aV[0];
219
220 if (IsUEdge) {
221 aUPar += aRatio*(aU[1] - aU[0]);
222 } else {
223 aVPar += aRatio*(aV[1] - aV[0]);
224 }
225
226 Extrema_POnSurfParams aParam(aUPar, aVPar, theSurf->Value(aUPar, aVPar));
227 Standard_Integer anIndices[2];
7fd59977 228
6060dd1f 229 theParam0.GetIndices(anIndices[0], anIndices[1]);
230 aParam.SetElementType(IsUEdge ? Extrema_UIsoEdge : Extrema_VIsoEdge);
231 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
232 aParam.SetIndices(anIndices[0], anIndices[1]);
233
234 return aParam;
235 }
236 }
237}
7fd59977 238
239//=============================================================================
240
241/*-----------------------------------------------------------------------------
92d1589b
A
242Function:
243 Find all extremum distances between point P and surface
244 S using sampling (NbU,NbV).
7fd59977 245
92d1589b 246Method:
0d969553
Y
247 The algorithm bases on the hypothesis that sampling is precise enough,
248 if there exist N extreme distances between the point and the surface,
249 so there also exist N extrema between the point and the grid.
92d1589b
A
250 So, the algorithm consists in starting from extrema of the grid to find the
251 extrema of the surface.
252 The extrema are calculated by the algorithm math_FunctionSetRoot with the
253 following arguments:
254 - F: Extrema_FuncExtPS created from P and S,
255 - UV: math_Vector the components which of are parameters of the extremum on the
256 grid,
257 - Tol: Min(TolU,TolV), (Prov.:math_FunctionSetRoot does not autorize a vector)
258 - UVinf: math_Vector the components which of are lower limits of u and v,
259 - UVsup: math_Vector the components which of are upper limits of u and v.
260
261Processing:
262 a- Creation of the table of distances (TbDist(0,NbU+1,0,NbV+1)):
263 The table is expanded at will; lines 0 and NbU+1 and
264 columns 0 and NbV+1 are initialized at RealFirst() or RealLast()
265 to simplify the tests carried out at stage b
266 (there is no need to test if the point is on border of the grid).
267 b- Calculation of extrema:
268 First the minimums and then the maximums are found. These 2 procedured
269 pass in a similar way:
270 b.a- Initialization:
271 - 'borders' of table TbDist (RealLast() in case of minimums
272 and RealLast() in case of maximums),
273 - table TbSel(0,NbU+1,0,NbV+1) of selection of points for
274 calculation of local extremum (0). When a point will selected,
275 it will not be selectable, as well as the ajacent points
276 (8 at least). The corresponding addresses will be set to 1.
277 b.b- Calculation of minimums (or maximums):
278 All distances from table TbDist are parsed in a loop:
279 - search minimum (or maximum) in the grid,
280 - calculate extremum on the surface,
281 - update table TbSel.
7fd59977 282-----------------------------------------------------------------------------*/
283
7fd59977 284Extrema_GenExtPS::Extrema_GenExtPS()
285{
286 myDone = Standard_False;
287 myInit = Standard_False;
92d1589b
A
288 myFlag = Extrema_ExtFlag_MINMAX;
289 myAlgo = Extrema_ExtAlgo_Grad;
7fd59977 290}
291
292
293Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
294 const Adaptor3d_Surface& S,
295 const Standard_Integer NbU,
296 const Standard_Integer NbV,
297 const Standard_Real TolU,
92d1589b
A
298 const Standard_Real TolV,
299 const Extrema_ExtFlag F,
300 const Extrema_ExtAlgo A)
301 : myF (P,S), myFlag(F), myAlgo(A)
7fd59977 302{
303 Initialize(S, NbU, NbV, TolU, TolV);
304 Perform(P);
305}
306
307Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
308 const Adaptor3d_Surface& S,
309 const Standard_Integer NbU,
310 const Standard_Integer NbV,
311 const Standard_Real Umin,
312 const Standard_Real Usup,
313 const Standard_Real Vmin,
314 const Standard_Real Vsup,
315 const Standard_Real TolU,
92d1589b
A
316 const Standard_Real TolV,
317 const Extrema_ExtFlag F,
318 const Extrema_ExtAlgo A)
319 : myF (P,S), myFlag(F), myAlgo(A)
7fd59977 320{
321 Initialize(S, NbU, NbV, Umin, Usup, Vmin, Vsup, TolU, TolV);
322 Perform(P);
323}
324
325
326void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
327 const Standard_Integer NbU,
328 const Standard_Integer NbV,
329 const Standard_Real TolU,
330 const Standard_Real TolV)
331{
332 myumin = S.FirstUParameter();
333 myusup = S.LastUParameter();
334 myvmin = S.FirstVParameter();
335 myvsup = S.LastVParameter();
336 Initialize(S,NbU,NbV,myumin,myusup,myvmin,myvsup,TolU,TolV);
337}
338
339
340void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
341 const Standard_Integer NbU,
342 const Standard_Integer NbV,
343 const Standard_Real Umin,
344 const Standard_Real Usup,
345 const Standard_Real Vmin,
346 const Standard_Real Vsup,
347 const Standard_Real TolU,
348 const Standard_Real TolV)
349{
7fd59977 350 myS = (Adaptor3d_SurfacePtr)&S;
351 myusample = NbU;
352 myvsample = NbV;
353 mytolu = TolU;
354 mytolv = TolV;
355 myumin = Umin;
356 myusup = Usup;
357 myvmin = Vmin;
358 myvsup = Vsup;
359
360 if ((myusample < 2) ||
361 (myvsample < 2)) { Standard_OutOfRange::Raise(); }
362
363 myF.Initialize(S);
364
82469411 365 mySphereUBTree.Nullify();
5368adff 366 myUParams.Nullify();
367 myVParams.Nullify();
368 myInit = Standard_False;
369}
7fd59977 370
5368adff 371inline static void fillParams(const TColStd_Array1OfReal& theKnots,
372 Standard_Integer theDegree,
373 Standard_Real theParMin,
374 Standard_Real theParMax,
375 Handle_TColStd_HArray1OfReal& theParams,
376 Standard_Integer theSample)
377{
378 NCollection_Vector<Standard_Real> aParams;
379 Standard_Integer i = 1;
380 Standard_Real aPrevPar = theParMin;
381 aParams.Append(aPrevPar);
382 //calculation the array of parametric points depending on the knots array variation and degree of given surface
383 for ( ; i < theKnots.Length() && theKnots(i) < (theParMax - Precision::PConfusion()); i++ )
92d1589b 384 {
5368adff 385 if ( theKnots(i+1) < theParMin + Precision::PConfusion())
386 continue;
387
388 Standard_Real aStep = (theKnots(i+1) - theKnots(i))/Max(theDegree,2);
389 Standard_Integer k =1;
390 for( ; k <= theDegree ; k++)
391 {
392 Standard_Real aPar = theKnots(i) + k * aStep;
393 if(aPar > theParMax - Precision::PConfusion())
394 break;
395 if(aPar > aPrevPar + Precision::PConfusion() )
396 {
397 aParams.Append(aPar);
398 aPrevPar = aPar;
399 }
400 }
401
402 }
403 aParams.Append(theParMax);
404 Standard_Integer nbPar = aParams.Length();
405 //in case of an insufficient number of points the grid will be built later
406 if (nbPar < theSample)
407 return;
408 theParams = new TColStd_HArray1OfReal(1, nbPar );
409 for( i = 0; i < nbPar; i++)
410 theParams->SetValue(i+1,aParams(i));
411}
412
413void Extrema_GenExtPS::GetGridPoints( const Adaptor3d_Surface& theSurf)
414{
415 //creation parametric points for BSpline and Bezier surfaces
416 //with taking into account of Degree and NbKnots of BSpline or Bezier geometry
417 if(theSurf.GetType() == GeomAbs_OffsetSurface)
418 GetGridPoints(theSurf.BasisSurface()->Surface());
419 //parametric points for BSpline surfaces
420 else if( theSurf.GetType() == GeomAbs_BSplineSurface)
421 {
422 Handle(Geom_BSplineSurface) aBspl = theSurf.BSpline();
423 if(!aBspl.IsNull())
424 {
425 TColStd_Array1OfReal aUKnots(1, aBspl->NbUKnots());
426 aBspl->UKnots( aUKnots);
427 TColStd_Array1OfReal aVKnots(1, aBspl->NbVKnots());
428 aBspl->VKnots( aVKnots);
429 fillParams(aUKnots,aBspl->UDegree(),myumin, myusup, myUParams, myusample);
430 fillParams(aVKnots,aBspl->VDegree(),myvmin, myvsup, myVParams, myvsample);
431 }
432 }
433 //calculation parametric points for Bezier surfaces
434 else if(theSurf.GetType() == GeomAbs_BezierSurface)
435 {
436 Handle(Geom_BezierSurface) aBezier = theSurf.Bezier();
437 if(aBezier.IsNull())
438 return;
439
440 TColStd_Array1OfReal aUKnots(1,2);
441 TColStd_Array1OfReal aVKnots(1,2);
442 aBezier->Bounds(aUKnots(1), aUKnots(2), aVKnots(1), aVKnots(2));
443 fillParams(aUKnots, aBezier->UDegree(), myumin, myusup, myUParams, myusample);
444 fillParams(aVKnots, aBezier->VDegree(), myvmin, myvsup, myVParams, myvsample);
7fd59977 445
5368adff 446 }
447 //creation points for surfaces based on BSpline or Bezier curves
448 else if(theSurf.GetType() == GeomAbs_SurfaceOfRevolution ||
449 theSurf.GetType() == GeomAbs_SurfaceOfExtrusion)
450 {
451 Handle(TColStd_HArray1OfReal) anArrKnots;
452 Standard_Integer aDegree = 0;
5368adff 453 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BSplineCurve)
454 {
455 Handle(Geom_BSplineCurve) aBspl = theSurf.BasisCurve()->Curve().BSpline();
456 if(!aBspl.IsNull())
457 {
458 anArrKnots = new TColStd_HArray1OfReal(1,aBspl->NbKnots());
459 aBspl->Knots( anArrKnots->ChangeArray1() );
460 aDegree = aBspl->Degree();
461
462 }
463
464 }
465 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BezierCurve)
466 {
467 Handle(Geom_BezierCurve) aBez = theSurf.BasisCurve()->Curve().Bezier();
468 if(!aBez.IsNull())
469 {
470 anArrKnots = new TColStd_HArray1OfReal(1,2);
471 anArrKnots->SetValue(1, aBez->FirstParameter());
472 anArrKnots->SetValue(2, aBez->LastParameter());
473 aDegree = aBez->Degree();
474
475 }
476 }
477 if(anArrKnots.IsNull())
478 return;
479 if( theSurf.GetType() == GeomAbs_SurfaceOfRevolution )
480 fillParams( anArrKnots->Array1(), aDegree, myvmin, myvsup, myVParams, myvsample);
481 else
482 fillParams( anArrKnots->Array1(), aDegree, myumin, myusup, myUParams, myusample);
483 }
484 //update the number of points in sample
485 if(!myUParams.IsNull())
486 myusample = myUParams->Length();
487 if( !myVParams.IsNull())
488 myvsample = myVParams->Length();
489
490}
491
6060dd1f 492void Extrema_GenExtPS::BuildGrid(const gp_Pnt &thePoint)
5368adff 493{
6060dd1f 494 Standard_Integer NoU, NoV;
495
496 //if grid was already built skip its creation
497 if (!myInit) {
498 //build parametric grid in case of a complex surface geometry (BSpline and Bezier surfaces)
499 GetGridPoints(*myS);
500
501 //build grid in other cases
502 if( myUParams.IsNull() )
503 {
504 Standard_Real PasU = myusup - myumin;
505 Standard_Real U0 = PasU / myusample / 100.;
506 PasU = (PasU - U0) / (myusample - 1);
507 U0 = U0/2. + myumin;
508 myUParams = new TColStd_HArray1OfReal(1,myusample );
509 Standard_Integer NoU;
510 Standard_Real U = U0;
511 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
512 myUParams->SetValue(NoU, U);
513 }
5368adff 514
6060dd1f 515 if( myVParams.IsNull())
516 {
517 Standard_Real PasV = myvsup - myvmin;
518 Standard_Real V0 = PasV / myvsample / 100.;
519 PasV = (PasV - V0) / (myvsample - 1);
520 V0 = V0/2. + myvmin;
521
522 myVParams = new TColStd_HArray1OfReal(1,myvsample );
523 Standard_Integer NoV;
524 Standard_Real V = V0;
525
526 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
527 myVParams->SetValue(NoV, V);
528 }
529
530 //If flag was changed and extrema not reinitialized Extrema would fail
531 myPoints = new Extrema_HArray2OfPOnSurfParams
532 (0, myusample + 1, 0, myvsample + 1);
533 // Calculation of distances
5368adff 534
6060dd1f 535 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
536 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
537 gp_Pnt aP1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
538 Extrema_POnSurfParams aParam
539 (myUParams->Value(NoU), myVParams->Value(NoV), aP1);
540
541 aParam.SetElementType(Extrema_Node);
542 aParam.SetIndices(NoU, NoV);
543 myPoints->SetValue(NoU, NoV, aParam);
544 }
545 }
5368adff 546
6060dd1f 547 // Fill boundary with negative square distance.
548 // It is used for computation of Maximum.
549 for (NoV = 0; NoV <= myvsample + 1; NoV++) {
550 myPoints->ChangeValue(0, NoV).SetSqrDistance(-1.);
551 myPoints->ChangeValue(myusample + 1, NoV).SetSqrDistance(-1.);
552 }
5368adff 553
6060dd1f 554 for (NoU = 1; NoU <= myusample; NoU++) {
555 myPoints->ChangeValue(NoU, 0).SetSqrDistance(-1.);
556 myPoints->ChangeValue(NoU, myvsample + 1).SetSqrDistance(-1.);
557 }
5368adff 558
6060dd1f 559 myInit = Standard_True;
5368adff 560 }
7fd59977 561
6060dd1f 562 // Compute distances to mesh.
563 // Step 1. Compute distances to nodes.
5368adff 564 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
565 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
6060dd1f 566 Extrema_POnSurfParams &aParam = myPoints->ChangeValue(NoU, NoV);
567
568 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
7fd59977 569 }
570 }
5368adff 571
6060dd1f 572 // For search of minimum compute distances to mesh.
573 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
574 {
575 // This is the tolerance of difference of squared values.
576 // No need to set it too small.
577 const Standard_Real aDiffTol = mytolu + mytolv;
578
579 // Step 2. Compute distances to edges.
580 // Assume UEdge(i, j) = { Point(i, j); Point(i + 1, j ) }
581 // Assume VEdge(i, j) = { Point(i, j); Point(i, j + 1) }
582 Handle(Extrema_HArray2OfPOnSurfParams) aUEdgePntParams =
583 new Extrema_HArray2OfPOnSurfParams(1, myusample - 1, 1, myvsample);
584 Handle(Extrema_HArray2OfPOnSurfParams) aVEdgePntParams =
585 new Extrema_HArray2OfPOnSurfParams(1, myusample, 1, myvsample - 1);
586
587 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
588 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
589 const Extrema_POnSurfParams &aParam0 = myPoints->Value(NoU, NoV);
590
591 if (NoU < myusample) {
592 // Compute parameters to UEdge.
593 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU + 1, NoV);
594 Extrema_POnSurfParams aUEdgeParam = ComputeEdgeParameters
595 (Standard_True, aParam0, aParam1, myS, thePoint, aDiffTol);
596
597 aUEdgePntParams->SetValue(NoU, NoV, aUEdgeParam);
598 }
92d1589b 599
6060dd1f 600 if (NoV < myvsample) {
601 // Compute parameters to VEdge.
602 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU, NoV + 1);
603 Extrema_POnSurfParams aVEdgeParam = ComputeEdgeParameters
604 (Standard_False, aParam0, aParam1, myS, thePoint, aDiffTol);
92d1589b 605
6060dd1f 606 aVEdgePntParams->SetValue(NoU, NoV, aVEdgeParam);
607 }
608 }
609 }
610
611 // Step 3. Compute distances to faces.
612 // Assume myFacePntParams(i, j) =
613 // { Point(i, j); Point(i + 1, j); Point(i + 1, j + 1); Point(i, j + 1) }
614 // Or
615 // { UEdge(i, j); VEdge(i + 1, j); UEdge(i, j + 1); VEdge(i, j) }
616 myFacePntParams =
617 new Extrema_HArray2OfPOnSurfParams(0, myusample, 0, myvsample);
618 Standard_Real aSqrDist01;
619 Standard_Real aDiffDist;
620 Standard_Boolean isOut;
621
622 for ( NoU = 1 ; NoU < myusample; NoU++ ) {
623 for ( NoV = 1 ; NoV < myvsample; NoV++) {
624 const Extrema_POnSurfParams &aUE0 = aUEdgePntParams->Value(NoU, NoV);
625 const Extrema_POnSurfParams &aUE1 = aUEdgePntParams->Value(NoU, NoV+1);
626 const Extrema_POnSurfParams &aVE0 = aVEdgePntParams->Value(NoU, NoV);
627 const Extrema_POnSurfParams &aVE1 = aVEdgePntParams->Value(NoU+1, NoV);
628
629 aSqrDist01 = aUE0.Value().SquareDistance(aUE1.Value());
630 aDiffDist = Abs(aUE0.GetSqrDistance() - aUE1.GetSqrDistance());
631 isOut = Standard_False;
632
633 if (aDiffDist >= aSqrDist01 - aDiffTol) {
634 // The projection is outside the face.
635 isOut = Standard_True;
636 } else {
637 aSqrDist01 = aVE0.Value().SquareDistance(aVE1.Value());
638 aDiffDist = Abs(aVE0.GetSqrDistance() - aVE1.GetSqrDistance());
639
640 if (aDiffDist >= aSqrDist01 - aDiffTol) {
641 // The projection is outside the face.
642 isOut = Standard_True;
643 }
644 }
645
646 if (isOut) {
647 // Get the closest point on an edge.
648 const Extrema_POnSurfParams &aUEMin =
649 aUE0.GetSqrDistance() < aUE1.GetSqrDistance() ? aUE0 : aUE1;
650 const Extrema_POnSurfParams &aVEMin =
651 aVE0.GetSqrDistance() < aVE1.GetSqrDistance() ? aVE0 : aVE1;
652 const Extrema_POnSurfParams &aEMin =
653 aUEMin.GetSqrDistance() < aVEMin.GetSqrDistance() ? aUEMin : aVEMin;
654
655 myFacePntParams->SetValue(NoU, NoV, aEMin);
656 } else {
657 // Find closest point inside the face.
658 Standard_Real aU[2];
659 Standard_Real aV[2];
660 Standard_Real aUPar;
661 Standard_Real aVPar;
662
663 // Compute U parameter.
664 aUE0.Parameter(aU[0], aV[0]);
665 aUE1.Parameter(aU[1], aV[1]);
666 aUPar = 0.5*(aU[0] + aU[1]);
667 // Compute V parameter.
668 aVE0.Parameter(aU[0], aV[0]);
669 aVE1.Parameter(aU[1], aV[1]);
670 aVPar = 0.5*(aV[0] + aV[1]);
671
672 Extrema_POnSurfParams aParam(aUPar, aVPar, myS->Value(aUPar, aVPar));
673
674 aParam.SetElementType(Extrema_Face);
675 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
676 aParam.SetIndices(NoU, NoV);
677 myFacePntParams->SetValue(NoU, NoV, aParam);
678 }
679 }
680 }
681
682 // Fill boundary with RealLast square distance.
683 for (NoV = 0; NoV <= myvsample; NoV++) {
684 myFacePntParams->ChangeValue(0, NoV).SetSqrDistance(RealLast());
685 myFacePntParams->ChangeValue(myusample, NoV).SetSqrDistance(RealLast());
686 }
687
688 for (NoU = 1; NoU < myusample; NoU++) {
689 myFacePntParams->ChangeValue(NoU, 0).SetSqrDistance(RealLast());
690 myFacePntParams->ChangeValue(NoU, myvsample).SetSqrDistance(RealLast());
691 }
692 }
693}
5368adff 694
92d1589b 695/*
0d969553 696a- Constitution of the table of distances (TbDist(0,myusample+1,0,myvsample+1)):
92d1589b
A
697 ---------------------------------------------------------------
698*/
699
0d969553 700// Parameterisation of the sample
92d1589b 701
92d1589b
A
702void Extrema_GenExtPS::BuildTree()
703{
82469411
A
704 // if tree already exists, assume it is already correctly filled
705 if ( ! mySphereUBTree.IsNull() )
706 return;
707
708 Standard_Real PasU = myusup - myumin;
709 Standard_Real PasV = myvsup - myvmin;
710 Standard_Real U0 = PasU / myusample / 100.;
711 Standard_Real V0 = PasV / myvsample / 100.;
712 gp_Pnt P1;
713 PasU = (PasU - U0) / (myusample - 1);
714 PasV = (PasV - V0) / (myvsample - 1);
715 U0 = U0/2. + myumin;
716 V0 = V0/2. + myvmin;
717
5368adff 718 //build grid of parametric points
719 myUParams = new TColStd_HArray1OfReal(1,myusample );
720 myVParams = new TColStd_HArray1OfReal(1,myvsample );
721 Standard_Integer NoU, NoV;
722 Standard_Real U = U0, V = V0;
723 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
724 myUParams->SetValue(NoU, U);
725 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
726 myVParams->SetValue(NoV, V);
727
0d969553 728 // Calculation of distances
82469411
A
729 mySphereUBTree = new Extrema_UBTreeOfSphere;
730 Extrema_UBTreeFillerOfSphere aFiller(*mySphereUBTree);
731 Standard_Integer i = 0;
5368adff 732
82469411 733 mySphereArray = new Bnd_HArray1OfSphere(0, myusample * myvsample);
5368adff 734
735 for ( NoU = 1; NoU <= myusample; NoU++ ) {
736 for ( NoV = 1; NoV <= myvsample; NoV++) {
737 P1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
82469411
A
738 Bnd_Sphere aSph(P1.XYZ(), 0/*mytolu < mytolv ? mytolu : mytolv*/, NoU, NoV);
739 aFiller.Add(i, aSph);
740 mySphereArray->SetValue( i, aSph );
741 i++;
742 }
743 }
744 aFiller.Fill();
92d1589b
A
745}
746
35e08fe8 747void Extrema_GenExtPS::FindSolution(const gp_Pnt& /*P*/,
6060dd1f 748 const Extrema_POnSurfParams &theParams)
92d1589b
A
749{
750 math_Vector Tol(1,2);
751 Tol(1) = mytolu;
752 Tol(2) = mytolv;
7fd59977 753
6060dd1f 754 math_Vector UV(1, 2);
6060dd1f 755 theParams.Parameter(UV(1), UV(2));
756
92d1589b
A
757 math_Vector UVinf(1,2), UVsup(1,2);
758 UVinf(1) = myumin;
759 UVinf(2) = myvmin;
760 UVsup(1) = myusup;
761 UVsup(2) = myvsup;
762
cc9d78db 763 const Standard_Integer aNbMaxIter = 100;
764 math_FunctionSetRoot S (myF, UV, Tol, UVinf, UVsup, aNbMaxIter);
92d1589b 765
92d1589b
A
766 myDone = Standard_True;
767}
768
769void Extrema_GenExtPS::SetFlag(const Extrema_ExtFlag F)
770{
771 myFlag = F;
772}
773
774void Extrema_GenExtPS::SetAlgo(const Extrema_ExtAlgo A)
775{
5368adff 776 if(myAlgo != A)
777 myInit = Standard_False;
92d1589b 778 myAlgo = A;
5368adff 779
92d1589b 780}
7fd59977 781
782void Extrema_GenExtPS::Perform(const gp_Pnt& P)
783{
784 myDone = Standard_False;
785 myF.SetPoint(P);
5368adff 786
92d1589b
A
787 if(myAlgo == Extrema_ExtAlgo_Grad)
788 {
6060dd1f 789 BuildGrid(P);
92d1589b 790 Standard_Integer NoU,NoV;
7fd59977 791
92d1589b
A
792 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
793 {
6060dd1f 794 Extrema_ElementType anElemType;
795 Standard_Integer iU;
796 Standard_Integer iV;
797 Standard_Integer iU2;
798 Standard_Integer iV2;
799 Standard_Boolean isMin;
800 Standard_Integer i;
801
802 for (NoU = 1; NoU < myusample; NoU++) {
803 for (NoV = 1; NoV < myvsample; NoV++) {
804 const Extrema_POnSurfParams &aParam =
805 myFacePntParams->Value(NoU, NoV);
806
807 isMin = Standard_False;
808 anElemType = aParam.GetElementType();
809
810 if (anElemType == Extrema_Face) {
811 isMin = Standard_True;
812 } else {
813 // Check if it is a boundary edge or corner vertex.
814 aParam.GetIndices(iU, iV);
815
816 if (anElemType == Extrema_UIsoEdge) {
817 isMin = (iV == 1 || iV == myvsample);
818 } else if (anElemType == Extrema_VIsoEdge) {
819 isMin = (iU == 1 || iU == myusample);
820 } else if (anElemType == Extrema_Node) {
821 isMin = (iU == 1 || iU == myusample) &&
822 (iV == 1 || iV == myvsample);
823 }
824
825 if (!isMin) {
826 // This is a middle element.
827 if (anElemType == Extrema_UIsoEdge ||
828 (anElemType == Extrema_Node && (iU == 1 || iU == myusample))) {
829 // Check the down face.
830 const Extrema_POnSurfParams &aDownParam =
831 myFacePntParams->Value(NoU, NoV - 1);
832
833 if (aDownParam.GetElementType() == anElemType) {
834 aDownParam.GetIndices(iU2, iV2);
835 isMin = (iU == iU2 && iV == iV2);
836 }
837 } else if (anElemType == Extrema_VIsoEdge ||
838 (anElemType == Extrema_Node && (iV == 1 || iV == myvsample))) {
839 // Check the right face.
840 const Extrema_POnSurfParams &aRightParam =
841 myFacePntParams->Value(NoU - 1, NoV);
842
843 if (aRightParam.GetElementType() == anElemType) {
844 aRightParam.GetIndices(iU2, iV2);
845 isMin = (iU == iU2 && iV == iV2);
846 }
847 } else if (iU == NoU && iV == NoV) {
848 // Check the lower-left node. For this purpose it is necessary
849 // to check lower-left, lower and left faces.
850 isMin = Standard_True;
851
852 const Extrema_POnSurfParams *anOtherParam[3] =
853 { &myFacePntParams->Value(NoU, NoV - 1), // Down
854 &myFacePntParams->Value(NoU - 1, NoV - 1), // Lower-left
855 &myFacePntParams->Value(NoU - 1, NoV) }; // Left
856
857 for (i = 0; i < 3 && isMin; i++) {
858 if (anOtherParam[i]->GetElementType() == Extrema_Node) {
859 anOtherParam[i]->GetIndices(iU2, iV2);
860 isMin = (iU == iU2 && iV == iV2);
861 } else {
862 isMin = Standard_False;
863 }
864 }
865 }
92d1589b 866 }
6060dd1f 867 }
868
869 if (isMin) {
870 FindSolution(P, aParam);
871 }
92d1589b
A
872 }
873 }
874 }
875
876 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
877 {
6060dd1f 878 Standard_Real Dist;
879
92d1589b
A
880 for (NoU = 1; NoU <= myusample; NoU++) {
881 for (NoV = 1; NoV <= myvsample; NoV++) {
6060dd1f 882 Dist = myPoints->Value(NoU, NoV).GetSqrDistance();
883 if ((myPoints->Value(NoU-1,NoV-1).GetSqrDistance() <= Dist) &&
884 (myPoints->Value(NoU-1,NoV ).GetSqrDistance() <= Dist) &&
885 (myPoints->Value(NoU-1,NoV+1).GetSqrDistance() <= Dist) &&
886 (myPoints->Value(NoU ,NoV-1).GetSqrDistance() <= Dist) &&
887 (myPoints->Value(NoU ,NoV+1).GetSqrDistance() <= Dist) &&
888 (myPoints->Value(NoU+1,NoV-1).GetSqrDistance() <= Dist) &&
889 (myPoints->Value(NoU+1,NoV ).GetSqrDistance() <= Dist) &&
890 (myPoints->Value(NoU+1,NoV+1).GetSqrDistance() <= Dist)) {
891 // Find maximum.
892 FindSolution(P, myPoints->Value(NoU, NoV));
893 }
894 }
92d1589b
A
895 }
896 }
7fd59977 897 }
92d1589b
A
898 else
899 {
900 BuildTree();
901 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
902 {
903 Bnd_Sphere aSol = mySphereArray->Value(0);
904 Bnd_SphereUBTreeSelectorMin aSelector(mySphereArray, aSol);
905 //aSelector.SetMaxDist( RealLast() );
906 aSelector.DefineCheckPoint( P );
302f96fb 907 mySphereUBTree->Select( aSelector );
92d1589b
A
908 //TODO: check if no solution in binary tree
909 Bnd_Sphere& aSph = aSelector.Sphere();
6060dd1f 910 Standard_Real aU = myUParams->Value(aSph.U());
911 Standard_Real aV = myVParams->Value(aSph.V());
912 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
92d1589b 913
6060dd1f 914 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
915 aParams.SetIndices(aSph.U(), aSph.V());
916 FindSolution(P, aParams);
92d1589b
A
917 }
918 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
919 {
920 Bnd_Sphere aSol = mySphereArray->Value(0);
921 Bnd_SphereUBTreeSelectorMax aSelector(mySphereArray, aSol);
922 //aSelector.SetMaxDist( RealLast() );
923 aSelector.DefineCheckPoint( P );
302f96fb 924 mySphereUBTree->Select( aSelector );
92d1589b
A
925 //TODO: check if no solution in binary tree
926 Bnd_Sphere& aSph = aSelector.Sphere();
6060dd1f 927 Standard_Real aU = myUParams->Value(aSph.U());
928 Standard_Real aV = myVParams->Value(aSph.V());
929 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
6060dd1f 930 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
931 aParams.SetIndices(aSph.U(), aSph.V());
92d1589b 932
6060dd1f 933 FindSolution(P, aParams);
7fd59977 934 }
935 }
7fd59977 936}
937//=============================================================================
938
939Standard_Boolean Extrema_GenExtPS::IsDone () const { return myDone; }
940//=============================================================================
941
942Standard_Integer Extrema_GenExtPS::NbExt () const
943{
944 if (!IsDone()) { StdFail_NotDone::Raise(); }
945 return myF.NbExt();
946}
947//=============================================================================
948
949Standard_Real Extrema_GenExtPS::SquareDistance (const Standard_Integer N) const
950{
951 if (!IsDone()) { StdFail_NotDone::Raise(); }
952 return myF.SquareDistance(N);
953}
954//=============================================================================
955
5d99f2c8 956const Extrema_POnSurf& Extrema_GenExtPS::Point (const Standard_Integer N) const
7fd59977 957{
958 if (!IsDone()) { StdFail_NotDone::Raise(); }
959 return myF.Point(N);
960}
961//=============================================================================