0031682: Visualization - Prs3d_ShadingAspect::SetTransparency() has no effect with...
[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
d533dafb 220Extrema_GenExtPS::Extrema_GenExtPS()
221: myumin(0.0),
222 myusup(0.0),
223 myvmin(0.0),
224 myvsup(0.0),
225 myusample(0),
226 myvsample(0),
227 mytolu(0.0),
228 mytolv(0.0),
229 myS(NULL)
7fd59977 230{
231 myDone = Standard_False;
232 myInit = Standard_False;
92d1589b
A
233 myFlag = Extrema_ExtFlag_MINMAX;
234 myAlgo = Extrema_ExtAlgo_Grad;
7fd59977 235}
236
237
238Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
150e93a7 239 const Adaptor3d_Surface& S,
240 const Standard_Integer NbU,
241 const Standard_Integer NbV,
242 const Standard_Real TolU,
243 const Standard_Real TolV,
244 const Extrema_ExtFlag F,
245 const Extrema_ExtAlgo A)
246: myF (P,S),
247 myFlag(F),
248 myAlgo(A)
7fd59977 249{
250 Initialize(S, NbU, NbV, TolU, TolV);
251 Perform(P);
252}
253
254Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
150e93a7 255 const Adaptor3d_Surface& S,
256 const Standard_Integer NbU,
257 const Standard_Integer NbV,
258 const Standard_Real Umin,
259 const Standard_Real Usup,
260 const Standard_Real Vmin,
261 const Standard_Real Vsup,
262 const Standard_Real TolU,
263 const Standard_Real TolV,
264 const Extrema_ExtFlag F,
265 const Extrema_ExtAlgo A)
266: myF (P,S),
267 myFlag(F),
268 myAlgo(A)
7fd59977 269{
270 Initialize(S, NbU, NbV, Umin, Usup, Vmin, Vsup, TolU, TolV);
271 Perform(P);
272}
273
274
275void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
150e93a7 276 const Standard_Integer NbU,
277 const Standard_Integer NbV,
278 const Standard_Real TolU,
279 const Standard_Real TolV)
7fd59977 280{
281 myumin = S.FirstUParameter();
282 myusup = S.LastUParameter();
283 myvmin = S.FirstVParameter();
284 myvsup = S.LastVParameter();
285 Initialize(S,NbU,NbV,myumin,myusup,myvmin,myvsup,TolU,TolV);
286}
287
288
289void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
150e93a7 290 const Standard_Integer NbU,
291 const Standard_Integer NbV,
292 const Standard_Real Umin,
293 const Standard_Real Usup,
294 const Standard_Real Vmin,
295 const Standard_Real Vsup,
296 const Standard_Real TolU,
297 const Standard_Real TolV)
7fd59977 298{
7fd59977 299 myS = (Adaptor3d_SurfacePtr)&S;
300 myusample = NbU;
301 myvsample = NbV;
302 mytolu = TolU;
303 mytolv = TolV;
304 myumin = Umin;
305 myusup = Usup;
306 myvmin = Vmin;
307 myvsup = Vsup;
308
309 if ((myusample < 2) ||
9775fa61 310 (myvsample < 2)) { throw Standard_OutOfRange(); }
7fd59977 311
312 myF.Initialize(S);
313
82469411 314 mySphereUBTree.Nullify();
5368adff 315 myUParams.Nullify();
316 myVParams.Nullify();
317 myInit = Standard_False;
318}
7fd59977 319
5368adff 320inline static void fillParams(const TColStd_Array1OfReal& theKnots,
321 Standard_Integer theDegree,
322 Standard_Real theParMin,
323 Standard_Real theParMax,
857ffd5e 324 Handle(TColStd_HArray1OfReal)& theParams,
5368adff 325 Standard_Integer theSample)
326{
327 NCollection_Vector<Standard_Real> aParams;
328 Standard_Integer i = 1;
329 Standard_Real aPrevPar = theParMin;
330 aParams.Append(aPrevPar);
331 //calculation the array of parametric points depending on the knots array variation and degree of given surface
332 for ( ; i < theKnots.Length() && theKnots(i) < (theParMax - Precision::PConfusion()); i++ )
92d1589b 333 {
5368adff 334 if ( theKnots(i+1) < theParMin + Precision::PConfusion())
335 continue;
336
337 Standard_Real aStep = (theKnots(i+1) - theKnots(i))/Max(theDegree,2);
338 Standard_Integer k =1;
339 for( ; k <= theDegree ; k++)
340 {
341 Standard_Real aPar = theKnots(i) + k * aStep;
342 if(aPar > theParMax - Precision::PConfusion())
343 break;
344 if(aPar > aPrevPar + Precision::PConfusion() )
345 {
346 aParams.Append(aPar);
347 aPrevPar = aPar;
348 }
349 }
350
351 }
352 aParams.Append(theParMax);
353 Standard_Integer nbPar = aParams.Length();
354 //in case of an insufficient number of points the grid will be built later
355 if (nbPar < theSample)
356 return;
357 theParams = new TColStd_HArray1OfReal(1, nbPar );
358 for( i = 0; i < nbPar; i++)
359 theParams->SetValue(i+1,aParams(i));
360}
361
362void Extrema_GenExtPS::GetGridPoints( const Adaptor3d_Surface& theSurf)
363{
364 //creation parametric points for BSpline and Bezier surfaces
365 //with taking into account of Degree and NbKnots of BSpline or Bezier geometry
366 if(theSurf.GetType() == GeomAbs_OffsetSurface)
367 GetGridPoints(theSurf.BasisSurface()->Surface());
368 //parametric points for BSpline surfaces
369 else if( theSurf.GetType() == GeomAbs_BSplineSurface)
370 {
371 Handle(Geom_BSplineSurface) aBspl = theSurf.BSpline();
372 if(!aBspl.IsNull())
373 {
374 TColStd_Array1OfReal aUKnots(1, aBspl->NbUKnots());
375 aBspl->UKnots( aUKnots);
376 TColStd_Array1OfReal aVKnots(1, aBspl->NbVKnots());
377 aBspl->VKnots( aVKnots);
378 fillParams(aUKnots,aBspl->UDegree(),myumin, myusup, myUParams, myusample);
379 fillParams(aVKnots,aBspl->VDegree(),myvmin, myvsup, myVParams, myvsample);
380 }
381 }
382 //calculation parametric points for Bezier surfaces
383 else if(theSurf.GetType() == GeomAbs_BezierSurface)
384 {
385 Handle(Geom_BezierSurface) aBezier = theSurf.Bezier();
386 if(aBezier.IsNull())
387 return;
388
389 TColStd_Array1OfReal aUKnots(1,2);
390 TColStd_Array1OfReal aVKnots(1,2);
391 aBezier->Bounds(aUKnots(1), aUKnots(2), aVKnots(1), aVKnots(2));
392 fillParams(aUKnots, aBezier->UDegree(), myumin, myusup, myUParams, myusample);
393 fillParams(aVKnots, aBezier->VDegree(), myvmin, myvsup, myVParams, myvsample);
7fd59977 394
5368adff 395 }
396 //creation points for surfaces based on BSpline or Bezier curves
397 else if(theSurf.GetType() == GeomAbs_SurfaceOfRevolution ||
398 theSurf.GetType() == GeomAbs_SurfaceOfExtrusion)
399 {
400 Handle(TColStd_HArray1OfReal) anArrKnots;
401 Standard_Integer aDegree = 0;
5368adff 402 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BSplineCurve)
403 {
404 Handle(Geom_BSplineCurve) aBspl = theSurf.BasisCurve()->Curve().BSpline();
405 if(!aBspl.IsNull())
406 {
407 anArrKnots = new TColStd_HArray1OfReal(1,aBspl->NbKnots());
408 aBspl->Knots( anArrKnots->ChangeArray1() );
409 aDegree = aBspl->Degree();
410
411 }
412
413 }
414 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BezierCurve)
415 {
416 Handle(Geom_BezierCurve) aBez = theSurf.BasisCurve()->Curve().Bezier();
417 if(!aBez.IsNull())
418 {
419 anArrKnots = new TColStd_HArray1OfReal(1,2);
420 anArrKnots->SetValue(1, aBez->FirstParameter());
421 anArrKnots->SetValue(2, aBez->LastParameter());
422 aDegree = aBez->Degree();
423
424 }
425 }
426 if(anArrKnots.IsNull())
427 return;
428 if( theSurf.GetType() == GeomAbs_SurfaceOfRevolution )
429 fillParams( anArrKnots->Array1(), aDegree, myvmin, myvsup, myVParams, myvsample);
430 else
431 fillParams( anArrKnots->Array1(), aDegree, myumin, myusup, myUParams, myusample);
432 }
433 //update the number of points in sample
434 if(!myUParams.IsNull())
435 myusample = myUParams->Length();
436 if( !myVParams.IsNull())
437 myvsample = myVParams->Length();
438
439}
440
150e93a7 441/*
442 * This function computes the point on surface parameters on edge.
443 * if it coincides with theParam0 or theParam1, it is returned.
444 */
445const Extrema_POnSurfParams& Extrema_GenExtPS::ComputeEdgeParameters
446 (const Standard_Boolean IsUEdge,
447 const Extrema_POnSurfParams &theParam0,
448 const Extrema_POnSurfParams &theParam1,
449 const gp_Pnt &thePoint,
450 const Standard_Real theDiffTol)
451{
452 const Standard_Real aSqrDist01 =
453 theParam0.Value().SquareDistance(theParam1.Value());
454
455 if (aSqrDist01 <= theDiffTol)
456 {
457 // The points are confused. Get the first point and change its type.
458 return theParam0;
459 }
460 else
461 {
462 const Standard_Real aDiffDist =
463 Abs(theParam0.GetSqrDistance() - theParam1.GetSqrDistance());
464
465 if (aDiffDist >= aSqrDist01 - theDiffTol)
466 {
467 // The shortest distance is one of the nodes.
468 if (theParam0.GetSqrDistance() > theParam1.GetSqrDistance())
469 {
470 // The shortest distance is the point 1.
471 return theParam1;
472 }
473 else
474 {
475 // The shortest distance is the point 0.
476 return theParam0;
477 }
478 }
479 else
480 {
481 // The shortest distance is inside the edge.
482 gp_XYZ aPoP(thePoint.XYZ().Subtracted(theParam0.Value().XYZ()));
483 gp_XYZ aPoP1(theParam1.Value().XYZ().Subtracted(theParam0.Value().XYZ()));
484 Standard_Real aRatio = aPoP.Dot(aPoP1)/aSqrDist01;
485 Standard_Real aU[2];
486 Standard_Real aV[2];
487
488 theParam0.Parameter(aU[0], aV[0]);
489 theParam1.Parameter(aU[1], aV[1]);
490
491 Standard_Real aUPar = aU[0];
492 Standard_Real aVPar = aV[0];
493
494 if (IsUEdge)
495 {
496 aUPar += aRatio*(aU[1] - aU[0]);
497 }
498 else
499 {
500 aVPar += aRatio*(aV[1] - aV[0]);
501 }
502
503 myGridParam.SetParameters(aUPar, aVPar, myS->Value(aUPar, aVPar));
504 Standard_Integer anIndices[2];
505
506 theParam0.GetIndices(anIndices[0], anIndices[1]);
507 myGridParam.SetElementType(IsUEdge ? Extrema_UIsoEdge : Extrema_VIsoEdge);
508 myGridParam.SetSqrDistance(thePoint.SquareDistance(myGridParam.Value()));
509 myGridParam.SetIndices(anIndices[0], anIndices[1]);
510 return myGridParam;
511 }
512 }
513}
514
6060dd1f 515void Extrema_GenExtPS::BuildGrid(const gp_Pnt &thePoint)
5368adff 516{
6060dd1f 517 Standard_Integer NoU, NoV;
518
519 //if grid was already built skip its creation
520 if (!myInit) {
521 //build parametric grid in case of a complex surface geometry (BSpline and Bezier surfaces)
522 GetGridPoints(*myS);
523
524 //build grid in other cases
525 if( myUParams.IsNull() )
526 {
527 Standard_Real PasU = myusup - myumin;
528 Standard_Real U0 = PasU / myusample / 100.;
529 PasU = (PasU - U0) / (myusample - 1);
530 U0 = U0/2. + myumin;
531 myUParams = new TColStd_HArray1OfReal(1,myusample );
6060dd1f 532 Standard_Real U = U0;
533 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
534 myUParams->SetValue(NoU, U);
535 }
5368adff 536
6060dd1f 537 if( myVParams.IsNull())
538 {
539 Standard_Real PasV = myvsup - myvmin;
540 Standard_Real V0 = PasV / myvsample / 100.;
541 PasV = (PasV - V0) / (myvsample - 1);
542 V0 = V0/2. + myvmin;
543
544 myVParams = new TColStd_HArray1OfReal(1,myvsample );
6060dd1f 545 Standard_Real V = V0;
546
547 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
548 myVParams->SetValue(NoV, V);
549 }
550
551 //If flag was changed and extrema not reinitialized Extrema would fail
552 myPoints = new Extrema_HArray2OfPOnSurfParams
553 (0, myusample + 1, 0, myvsample + 1);
554 // Calculation of distances
5368adff 555
6060dd1f 556 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
557 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
558 gp_Pnt aP1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
559 Extrema_POnSurfParams aParam
560 (myUParams->Value(NoU), myVParams->Value(NoV), aP1);
561
562 aParam.SetElementType(Extrema_Node);
563 aParam.SetIndices(NoU, NoV);
564 myPoints->SetValue(NoU, NoV, aParam);
565 }
566 }
5368adff 567
150e93a7 568 myFacePntParams =
569 new Extrema_HArray2OfPOnSurfParams(0, myusample, 0, myvsample);
570
571 myUEdgePntParams =
572 new Extrema_HArray2OfPOnSurfParams(1, myusample - 1, 1, myvsample);
573 myVEdgePntParams =
574 new Extrema_HArray2OfPOnSurfParams(1, myusample, 1, myvsample - 1);
575
6060dd1f 576 // Fill boundary with negative square distance.
577 // It is used for computation of Maximum.
578 for (NoV = 0; NoV <= myvsample + 1; NoV++) {
579 myPoints->ChangeValue(0, NoV).SetSqrDistance(-1.);
580 myPoints->ChangeValue(myusample + 1, NoV).SetSqrDistance(-1.);
581 }
5368adff 582
6060dd1f 583 for (NoU = 1; NoU <= myusample; NoU++) {
584 myPoints->ChangeValue(NoU, 0).SetSqrDistance(-1.);
585 myPoints->ChangeValue(NoU, myvsample + 1).SetSqrDistance(-1.);
586 }
5368adff 587
6060dd1f 588 myInit = Standard_True;
5368adff 589 }
7fd59977 590
6060dd1f 591 // Compute distances to mesh.
592 // Step 1. Compute distances to nodes.
5368adff 593 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
594 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
6060dd1f 595 Extrema_POnSurfParams &aParam = myPoints->ChangeValue(NoU, NoV);
596
597 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
7fd59977 598 }
599 }
5368adff 600
6060dd1f 601 // For search of minimum compute distances to mesh.
602 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
603 {
604 // This is the tolerance of difference of squared values.
605 // No need to set it too small.
606 const Standard_Real aDiffTol = mytolu + mytolv;
607
608 // Step 2. Compute distances to edges.
609 // Assume UEdge(i, j) = { Point(i, j); Point(i + 1, j ) }
610 // Assume VEdge(i, j) = { Point(i, j); Point(i, j + 1) }
150e93a7 611 for ( NoU = 1 ; NoU <= myusample; NoU++ )
612 {
613 for ( NoV = 1 ; NoV <= myvsample; NoV++)
614 {
6060dd1f 615 const Extrema_POnSurfParams &aParam0 = myPoints->Value(NoU, NoV);
616
150e93a7 617 if (NoU < myusample)
618 {
6060dd1f 619 // Compute parameters to UEdge.
620 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU + 1, NoV);
150e93a7 621 const Extrema_POnSurfParams &anEdgeParam = ComputeEdgeParameters(Standard_True, aParam0, aParam1, thePoint, aDiffTol);
6060dd1f 622
150e93a7 623 myUEdgePntParams->SetValue(NoU, NoV, anEdgeParam);
6060dd1f 624 }
92d1589b 625
150e93a7 626 if (NoV < myvsample)
627 {
6060dd1f 628 // Compute parameters to VEdge.
629 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU, NoV + 1);
150e93a7 630 const Extrema_POnSurfParams &anEdgeParam = ComputeEdgeParameters(Standard_False, aParam0, aParam1, thePoint, aDiffTol);
92d1589b 631
150e93a7 632 myVEdgePntParams->SetValue(NoU, NoV, anEdgeParam);
6060dd1f 633 }
634 }
635 }
636
637 // Step 3. Compute distances to faces.
638 // Assume myFacePntParams(i, j) =
639 // { Point(i, j); Point(i + 1, j); Point(i + 1, j + 1); Point(i, j + 1) }
640 // Or
641 // { UEdge(i, j); VEdge(i + 1, j); UEdge(i, j + 1); VEdge(i, j) }
6060dd1f 642 Standard_Real aSqrDist01;
643 Standard_Real aDiffDist;
644 Standard_Boolean isOut;
645
646 for ( NoU = 1 ; NoU < myusample; NoU++ ) {
647 for ( NoV = 1 ; NoV < myvsample; NoV++) {
150e93a7 648 const Extrema_POnSurfParams &aUE0 = myUEdgePntParams->Value(NoU, NoV);
649 const Extrema_POnSurfParams &aUE1 = myUEdgePntParams->Value(NoU, NoV+1);
650 const Extrema_POnSurfParams &aVE0 = myVEdgePntParams->Value(NoU, NoV);
651 const Extrema_POnSurfParams &aVE1 = myVEdgePntParams->Value(NoU+1, NoV);
6060dd1f 652
653 aSqrDist01 = aUE0.Value().SquareDistance(aUE1.Value());
654 aDiffDist = Abs(aUE0.GetSqrDistance() - aUE1.GetSqrDistance());
655 isOut = Standard_False;
656
657 if (aDiffDist >= aSqrDist01 - aDiffTol) {
658 // The projection is outside the face.
659 isOut = Standard_True;
660 } else {
661 aSqrDist01 = aVE0.Value().SquareDistance(aVE1.Value());
662 aDiffDist = Abs(aVE0.GetSqrDistance() - aVE1.GetSqrDistance());
663
664 if (aDiffDist >= aSqrDist01 - aDiffTol) {
665 // The projection is outside the face.
666 isOut = Standard_True;
667 }
668 }
669
670 if (isOut) {
671 // Get the closest point on an edge.
672 const Extrema_POnSurfParams &aUEMin =
673 aUE0.GetSqrDistance() < aUE1.GetSqrDistance() ? aUE0 : aUE1;
674 const Extrema_POnSurfParams &aVEMin =
675 aVE0.GetSqrDistance() < aVE1.GetSqrDistance() ? aVE0 : aVE1;
676 const Extrema_POnSurfParams &aEMin =
677 aUEMin.GetSqrDistance() < aVEMin.GetSqrDistance() ? aUEMin : aVEMin;
678
679 myFacePntParams->SetValue(NoU, NoV, aEMin);
680 } else {
681 // Find closest point inside the face.
682 Standard_Real aU[2];
683 Standard_Real aV[2];
684 Standard_Real aUPar;
685 Standard_Real aVPar;
686
687 // Compute U parameter.
688 aUE0.Parameter(aU[0], aV[0]);
689 aUE1.Parameter(aU[1], aV[1]);
690 aUPar = 0.5*(aU[0] + aU[1]);
691 // Compute V parameter.
692 aVE0.Parameter(aU[0], aV[0]);
693 aVE1.Parameter(aU[1], aV[1]);
694 aVPar = 0.5*(aV[0] + aV[1]);
695
696 Extrema_POnSurfParams aParam(aUPar, aVPar, myS->Value(aUPar, aVPar));
697
698 aParam.SetElementType(Extrema_Face);
699 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
700 aParam.SetIndices(NoU, NoV);
701 myFacePntParams->SetValue(NoU, NoV, aParam);
702 }
703 }
704 }
705
706 // Fill boundary with RealLast square distance.
707 for (NoV = 0; NoV <= myvsample; NoV++) {
708 myFacePntParams->ChangeValue(0, NoV).SetSqrDistance(RealLast());
709 myFacePntParams->ChangeValue(myusample, NoV).SetSqrDistance(RealLast());
710 }
711
712 for (NoU = 1; NoU < myusample; NoU++) {
713 myFacePntParams->ChangeValue(NoU, 0).SetSqrDistance(RealLast());
714 myFacePntParams->ChangeValue(NoU, myvsample).SetSqrDistance(RealLast());
715 }
716 }
717}
5368adff 718
638ad7f3 719// Parametrization of the sample
92d1589b
A
720void Extrema_GenExtPS::BuildTree()
721{
82469411
A
722 // if tree already exists, assume it is already correctly filled
723 if ( ! mySphereUBTree.IsNull() )
724 return;
725
59fcbcae 726 if (myS->GetType() == GeomAbs_BSplineSurface) {
727 Handle(Geom_BSplineSurface) aBspl = myS->BSpline();
728 Standard_Integer aUValue = aBspl->UDegree() * aBspl->NbUKnots();
729 Standard_Integer aVValue = aBspl->VDegree() * aBspl->NbVKnots();
730 if (aUValue > myusample)
731 myusample = aUValue;
732 if (aVValue > myvsample)
733 myvsample = aVValue;
734 }
735
82469411
A
736 Standard_Real PasU = myusup - myumin;
737 Standard_Real PasV = myvsup - myvmin;
738 Standard_Real U0 = PasU / myusample / 100.;
739 Standard_Real V0 = PasV / myvsample / 100.;
740 gp_Pnt P1;
741 PasU = (PasU - U0) / (myusample - 1);
742 PasV = (PasV - V0) / (myvsample - 1);
743 U0 = U0/2. + myumin;
744 V0 = V0/2. + myvmin;
745
5368adff 746 //build grid of parametric points
747 myUParams = new TColStd_HArray1OfReal(1,myusample );
748 myVParams = new TColStd_HArray1OfReal(1,myvsample );
749 Standard_Integer NoU, NoV;
750 Standard_Real U = U0, V = V0;
751 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
752 myUParams->SetValue(NoU, U);
753 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
754 myVParams->SetValue(NoV, V);
755
0d969553 756 // Calculation of distances
82469411
A
757 mySphereUBTree = new Extrema_UBTreeOfSphere;
758 Extrema_UBTreeFillerOfSphere aFiller(*mySphereUBTree);
759 Standard_Integer i = 0;
5368adff 760
82469411 761 mySphereArray = new Bnd_HArray1OfSphere(0, myusample * myvsample);
5368adff 762
763 for ( NoU = 1; NoU <= myusample; NoU++ ) {
764 for ( NoV = 1; NoV <= myvsample; NoV++) {
765 P1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
82469411
A
766 Bnd_Sphere aSph(P1.XYZ(), 0/*mytolu < mytolv ? mytolu : mytolv*/, NoU, NoV);
767 aFiller.Add(i, aSph);
768 mySphereArray->SetValue( i, aSph );
769 i++;
770 }
771 }
772 aFiller.Fill();
92d1589b
A
773}
774
35e08fe8 775void Extrema_GenExtPS::FindSolution(const gp_Pnt& /*P*/,
6060dd1f 776 const Extrema_POnSurfParams &theParams)
92d1589b
A
777{
778 math_Vector Tol(1,2);
779 Tol(1) = mytolu;
780 Tol(2) = mytolv;
7fd59977 781
6060dd1f 782 math_Vector UV(1, 2);
6060dd1f 783 theParams.Parameter(UV(1), UV(2));
784
92d1589b
A
785 math_Vector UVinf(1,2), UVsup(1,2);
786 UVinf(1) = myumin;
787 UVinf(2) = myvmin;
788 UVsup(1) = myusup;
789 UVsup(2) = myvsup;
790
859a47c3 791 math_FunctionSetRoot S(myF, Tol);
792 S.Perform(myF, UV, UVinf, UVsup);
92d1589b 793
92d1589b
A
794 myDone = Standard_True;
795}
796
797void Extrema_GenExtPS::SetFlag(const Extrema_ExtFlag F)
798{
799 myFlag = F;
800}
801
802void Extrema_GenExtPS::SetAlgo(const Extrema_ExtAlgo A)
803{
5368adff 804 if(myAlgo != A)
805 myInit = Standard_False;
92d1589b 806 myAlgo = A;
5368adff 807
92d1589b 808}
7fd59977 809
810void Extrema_GenExtPS::Perform(const gp_Pnt& P)
811{
812 myDone = Standard_False;
813 myF.SetPoint(P);
5368adff 814
92d1589b
A
815 if(myAlgo == Extrema_ExtAlgo_Grad)
816 {
6060dd1f 817 BuildGrid(P);
92d1589b 818 Standard_Integer NoU,NoV;
7fd59977 819
92d1589b
A
820 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
821 {
6060dd1f 822 Extrema_ElementType anElemType;
823 Standard_Integer iU;
824 Standard_Integer iV;
825 Standard_Integer iU2;
826 Standard_Integer iV2;
827 Standard_Boolean isMin;
828 Standard_Integer i;
829
830 for (NoU = 1; NoU < myusample; NoU++) {
831 for (NoV = 1; NoV < myvsample; NoV++) {
832 const Extrema_POnSurfParams &aParam =
833 myFacePntParams->Value(NoU, NoV);
834
835 isMin = Standard_False;
836 anElemType = aParam.GetElementType();
837
838 if (anElemType == Extrema_Face) {
839 isMin = Standard_True;
840 } else {
841 // Check if it is a boundary edge or corner vertex.
842 aParam.GetIndices(iU, iV);
843
844 if (anElemType == Extrema_UIsoEdge) {
845 isMin = (iV == 1 || iV == myvsample);
846 } else if (anElemType == Extrema_VIsoEdge) {
847 isMin = (iU == 1 || iU == myusample);
848 } else if (anElemType == Extrema_Node) {
849 isMin = (iU == 1 || iU == myusample) &&
850 (iV == 1 || iV == myvsample);
851 }
852
853 if (!isMin) {
854 // This is a middle element.
855 if (anElemType == Extrema_UIsoEdge ||
856 (anElemType == Extrema_Node && (iU == 1 || iU == myusample))) {
857 // Check the down face.
858 const Extrema_POnSurfParams &aDownParam =
859 myFacePntParams->Value(NoU, NoV - 1);
860
861 if (aDownParam.GetElementType() == anElemType) {
862 aDownParam.GetIndices(iU2, iV2);
863 isMin = (iU == iU2 && iV == iV2);
864 }
865 } else if (anElemType == Extrema_VIsoEdge ||
866 (anElemType == Extrema_Node && (iV == 1 || iV == myvsample))) {
867 // Check the right face.
868 const Extrema_POnSurfParams &aRightParam =
869 myFacePntParams->Value(NoU - 1, NoV);
870
871 if (aRightParam.GetElementType() == anElemType) {
872 aRightParam.GetIndices(iU2, iV2);
873 isMin = (iU == iU2 && iV == iV2);
874 }
875 } else if (iU == NoU && iV == NoV) {
876 // Check the lower-left node. For this purpose it is necessary
877 // to check lower-left, lower and left faces.
878 isMin = Standard_True;
879
880 const Extrema_POnSurfParams *anOtherParam[3] =
881 { &myFacePntParams->Value(NoU, NoV - 1), // Down
882 &myFacePntParams->Value(NoU - 1, NoV - 1), // Lower-left
883 &myFacePntParams->Value(NoU - 1, NoV) }; // Left
884
885 for (i = 0; i < 3 && isMin; i++) {
886 if (anOtherParam[i]->GetElementType() == Extrema_Node) {
887 anOtherParam[i]->GetIndices(iU2, iV2);
888 isMin = (iU == iU2 && iV == iV2);
889 } else {
890 isMin = Standard_False;
891 }
892 }
893 }
92d1589b 894 }
6060dd1f 895 }
896
897 if (isMin) {
898 FindSolution(P, aParam);
899 }
92d1589b
A
900 }
901 }
902 }
903
904 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
905 {
6060dd1f 906 Standard_Real Dist;
907
370101f3 908 for (NoU = 1; NoU <= myusample; NoU++)
909 {
910 for (NoV = 1; NoV <= myvsample; NoV++)
911 {
912 const Extrema_POnSurfParams &aParamMain = myPoints->Value(NoU, NoV);
913 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU - 1, NoV - 1);
914 const Extrema_POnSurfParams &aParam2 = myPoints->Value(NoU - 1, NoV);
915 const Extrema_POnSurfParams &aParam3 = myPoints->Value(NoU - 1, NoV + 1);
916 const Extrema_POnSurfParams &aParam4 = myPoints->Value(NoU, NoV - 1);
917 const Extrema_POnSurfParams &aParam5 = myPoints->Value(NoU, NoV + 1);
918 const Extrema_POnSurfParams &aParam6 = myPoints->Value(NoU + 1, NoV - 1);
919 const Extrema_POnSurfParams &aParam7 = myPoints->Value(NoU + 1, NoV);
920 const Extrema_POnSurfParams &aParam8 = myPoints->Value(NoU + 1, NoV + 1);
921
922 Dist = aParamMain.GetSqrDistance();
923
924 if ((aParam1.GetSqrDistance() <= Dist) &&
925 (aParam2.GetSqrDistance() <= Dist) &&
926 (aParam3.GetSqrDistance() <= Dist) &&
927 (aParam4.GetSqrDistance() <= Dist) &&
928 (aParam5.GetSqrDistance() <= Dist) &&
929 (aParam6.GetSqrDistance() <= Dist) &&
930 (aParam7.GetSqrDistance() <= Dist) &&
931 (aParam8.GetSqrDistance() <= Dist))
932 {
6060dd1f 933 // Find maximum.
934 FindSolution(P, myPoints->Value(NoU, NoV));
935 }
936 }
92d1589b
A
937 }
938 }
7fd59977 939 }
92d1589b
A
940 else
941 {
942 BuildTree();
943 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
944 {
945 Bnd_Sphere aSol = mySphereArray->Value(0);
946 Bnd_SphereUBTreeSelectorMin aSelector(mySphereArray, aSol);
947 //aSelector.SetMaxDist( RealLast() );
948 aSelector.DefineCheckPoint( P );
302f96fb 949 mySphereUBTree->Select( aSelector );
92d1589b
A
950 //TODO: check if no solution in binary tree
951 Bnd_Sphere& aSph = aSelector.Sphere();
6060dd1f 952 Standard_Real aU = myUParams->Value(aSph.U());
953 Standard_Real aV = myVParams->Value(aSph.V());
954 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
92d1589b 955
6060dd1f 956 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
957 aParams.SetIndices(aSph.U(), aSph.V());
958 FindSolution(P, aParams);
92d1589b
A
959 }
960 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
961 {
962 Bnd_Sphere aSol = mySphereArray->Value(0);
963 Bnd_SphereUBTreeSelectorMax aSelector(mySphereArray, aSol);
964 //aSelector.SetMaxDist( RealLast() );
965 aSelector.DefineCheckPoint( P );
302f96fb 966 mySphereUBTree->Select( aSelector );
92d1589b
A
967 //TODO: check if no solution in binary tree
968 Bnd_Sphere& aSph = aSelector.Sphere();
6060dd1f 969 Standard_Real aU = myUParams->Value(aSph.U());
970 Standard_Real aV = myVParams->Value(aSph.V());
971 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
6060dd1f 972 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
973 aParams.SetIndices(aSph.U(), aSph.V());
92d1589b 974
6060dd1f 975 FindSolution(P, aParams);
7fd59977 976 }
977 }
7fd59977 978}
979//=============================================================================
980
981Standard_Boolean Extrema_GenExtPS::IsDone () const { return myDone; }
982//=============================================================================
983
984Standard_Integer Extrema_GenExtPS::NbExt () const
985{
9775fa61 986 if (!IsDone()) { throw StdFail_NotDone(); }
7fd59977 987 return myF.NbExt();
988}
989//=============================================================================
990
991Standard_Real Extrema_GenExtPS::SquareDistance (const Standard_Integer N) const
992{
638ad7f3 993 if ((N < 1) || (N > NbExt()))
994 {
995 throw Standard_OutOfRange();
996 }
997
7fd59977 998 return myF.SquareDistance(N);
999}
1000//=============================================================================
1001
5d99f2c8 1002const Extrema_POnSurf& Extrema_GenExtPS::Point (const Standard_Integer N) const
7fd59977 1003{
638ad7f3 1004 if ((N < 1) || (N > NbExt()))
1005 {
1006 throw Standard_OutOfRange();
1007 }
1008
7fd59977 1009 return myF.Point(N);
1010}
1011//=============================================================================