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