1 // Created on: 1995-07-18
2 // Created by: Modelistation
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
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
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 // Modified by skv - Thu Sep 30 15:21:07 2004 OCC593
20 #include <Extrema_GenExtPS.ixx>
21 #include <StdFail_NotDone.hxx>
22 #include <Standard_OutOfRange.hxx>
23 #include <TColStd_Array2OfInteger.hxx>
24 #include <TColStd_Array2OfReal.hxx>
25 #include <TColgp_Array2OfPnt.hxx>
26 #include <math_FunctionSetRoot.hxx>
27 #include <math_Vector.hxx>
28 #include <math_NewtonFunctionSetRoot.hxx>
29 #include <GeomAbs_IsoType.hxx>
30 #include <Bnd_Sphere.hxx>
31 #include <Extrema_HUBTreeOfSphere.hxx>
32 #include <Extrema_ExtFlag.hxx>
33 #include <Bnd_Array1OfSphere.hxx>
34 #include <Bnd_HArray1OfSphere.hxx>
35 #include <Precision.hxx>
36 #include <Geom_OffsetSurface.hxx>
37 #include <Geom_RectangularTrimmedSurface.hxx>
38 #include <Geom_BSplineSurface.hxx>
39 #include <Geom_BezierSurface.hxx>
40 #include <Adaptor3d_HSurface.hxx>
41 #include <Adaptor3d_HCurve.hxx>
42 #include <Adaptor3d_Curve.hxx>
43 #include <Geom_BSplineCurve.hxx>
44 #include <Geom_BezierCurve.hxx>
45 //IMPLEMENT_HARRAY1(Extrema_HArray1OfSphere)
48 class Bnd_SphereUBTreeSelector : public Extrema_UBTreeOfSphere::Selector
52 Bnd_SphereUBTreeSelector (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
55 mySphereArray(theSphereArray),
60 void DefineCheckPoint( const gp_Pnt& theXYZ )
63 Bnd_Sphere& Sphere() const
66 virtual Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const = 0;
68 virtual Standard_Boolean Accept(const Standard_Integer& theObj) = 0;
71 const Handle(Bnd_HArray1OfSphere)& mySphereArray;
74 void operator= (const Bnd_SphereUBTreeSelector&);
78 class Bnd_SphereUBTreeSelectorMin : public Bnd_SphereUBTreeSelector
81 Bnd_SphereUBTreeSelectorMin (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
83 : Bnd_SphereUBTreeSelector(theSphereArray, theSol),
87 void SetMinDist( const Standard_Real theMinDist )
88 { myMinDist = theMinDist; }
90 Standard_Real MinDist() const
93 Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const
95 Bnd_SphereUBTreeSelectorMin* me =
96 const_cast<Bnd_SphereUBTreeSelectorMin*>(this);
97 // myMinDist is decreased each time a nearer object is found
98 return theBnd.IsOut( myXYZ.XYZ(), me->myMinDist );
101 Standard_Boolean Accept(const Standard_Integer&);
104 Standard_Real myMinDist;
107 Standard_Boolean Bnd_SphereUBTreeSelectorMin::Accept(const Standard_Integer& theInd)
109 const Bnd_Sphere& aSph = mySphereArray->Value(theInd);
110 Standard_Real aCurDist;
112 // if ( (aCurDist = aSph.SquareDistance(myXYZ.XYZ())) < mySol.SquareDistance(myXYZ.XYZ()) )
113 if ( (aCurDist = aSph.Distance(myXYZ.XYZ())) < mySol.Distance(myXYZ.XYZ()) )
116 if ( aCurDist < myMinDist )
117 myMinDist = aCurDist;
119 return Standard_True;
122 return Standard_False;
125 class Bnd_SphereUBTreeSelectorMax : public Bnd_SphereUBTreeSelector
128 Bnd_SphereUBTreeSelectorMax (const Handle(Bnd_HArray1OfSphere)& theSphereArray,
130 : Bnd_SphereUBTreeSelector(theSphereArray, theSol),
134 void SetMaxDist( const Standard_Real theMaxDist )
135 { myMaxDist = theMaxDist; }
137 Standard_Real MaxDist() const
138 { return myMaxDist; }
140 Standard_Boolean Reject( const Bnd_Sphere &theBnd ) const
142 Bnd_SphereUBTreeSelectorMax* me =
143 const_cast<Bnd_SphereUBTreeSelectorMax*>(this);
144 // myMaxDist is decreased each time a nearer object is found
145 return theBnd.IsOut( myXYZ.XYZ(), me->myMaxDist );
148 Standard_Boolean Accept(const Standard_Integer&);
151 Standard_Real myMaxDist;
154 Standard_Boolean Bnd_SphereUBTreeSelectorMax::Accept(const Standard_Integer& theInd)
156 const Bnd_Sphere& aSph = mySphereArray->Value(theInd);
157 Standard_Real aCurDist;
159 // if ( (aCurDist = aSph.SquareDistance(myXYZ.XYZ())) > mySol.SquareDistance(myXYZ.XYZ()) )
160 if ( (aCurDist = aSph.Distance(myXYZ.XYZ())) > mySol.Distance(myXYZ.XYZ()) )
163 if ( aCurDist > myMaxDist )
164 myMaxDist = aCurDist;
166 return Standard_True;
169 return Standard_False;
172 //=============================================================================
174 /*-----------------------------------------------------------------------------
176 Find all extremum distances between point P and surface
177 S using sampling (NbU,NbV).
180 The algorithm bases on the hypothesis that sampling is precise enough,
181 if there exist N extreme distances between the point and the surface,
182 so there also exist N extrema between the point and the grid.
183 So, the algorithm consists in starting from extrema of the grid to find the
184 extrema of the surface.
185 The extrema are calculated by the algorithm math_FunctionSetRoot with the
187 - F: Extrema_FuncExtPS created from P and S,
188 - UV: math_Vector the components which of are parameters of the extremum on the
190 - Tol: Min(TolU,TolV), (Prov.:math_FunctionSetRoot does not autorize a vector)
191 - UVinf: math_Vector the components which of are lower limits of u and v,
192 - UVsup: math_Vector the components which of are upper limits of u and v.
195 a- Creation of the table of distances (TbDist(0,NbU+1,0,NbV+1)):
196 The table is expanded at will; lines 0 and NbU+1 and
197 columns 0 and NbV+1 are initialized at RealFirst() or RealLast()
198 to simplify the tests carried out at stage b
199 (there is no need to test if the point is on border of the grid).
200 b- Calculation of extrema:
201 First the minimums and then the maximums are found. These 2 procedured
202 pass in a similar way:
204 - 'borders' of table TbDist (RealLast() in case of minimums
205 and RealLast() in case of maximums),
206 - table TbSel(0,NbU+1,0,NbV+1) of selection of points for
207 calculation of local extremum (0). When a point will selected,
208 it will not be selectable, as well as the ajacent points
209 (8 at least). The corresponding addresses will be set to 1.
210 b.b- Calculation of minimums (or maximums):
211 All distances from table TbDist are parsed in a loop:
212 - search minimum (or maximum) in the grid,
213 - calculate extremum on the surface,
214 - update table TbSel.
215 -----------------------------------------------------------------------------*/
217 Extrema_GenExtPS::Extrema_GenExtPS()
219 myDone = Standard_False;
220 myInit = Standard_False;
221 myFlag = Extrema_ExtFlag_MINMAX;
222 myAlgo = Extrema_ExtAlgo_Grad;
226 Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
227 const Adaptor3d_Surface& S,
228 const Standard_Integer NbU,
229 const Standard_Integer NbV,
230 const Standard_Real TolU,
231 const Standard_Real TolV,
232 const Extrema_ExtFlag F,
233 const Extrema_ExtAlgo A)
238 Initialize(S, NbU, NbV, TolU, TolV);
242 Extrema_GenExtPS::Extrema_GenExtPS (const gp_Pnt& P,
243 const Adaptor3d_Surface& S,
244 const Standard_Integer NbU,
245 const Standard_Integer NbV,
246 const Standard_Real Umin,
247 const Standard_Real Usup,
248 const Standard_Real Vmin,
249 const Standard_Real Vsup,
250 const Standard_Real TolU,
251 const Standard_Real TolV,
252 const Extrema_ExtFlag F,
253 const Extrema_ExtAlgo A)
258 Initialize(S, NbU, NbV, Umin, Usup, Vmin, Vsup, TolU, TolV);
263 void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
264 const Standard_Integer NbU,
265 const Standard_Integer NbV,
266 const Standard_Real TolU,
267 const Standard_Real TolV)
269 myumin = S.FirstUParameter();
270 myusup = S.LastUParameter();
271 myvmin = S.FirstVParameter();
272 myvsup = S.LastVParameter();
273 Initialize(S,NbU,NbV,myumin,myusup,myvmin,myvsup,TolU,TolV);
277 void Extrema_GenExtPS::Initialize(const Adaptor3d_Surface& S,
278 const Standard_Integer NbU,
279 const Standard_Integer NbV,
280 const Standard_Real Umin,
281 const Standard_Real Usup,
282 const Standard_Real Vmin,
283 const Standard_Real Vsup,
284 const Standard_Real TolU,
285 const Standard_Real TolV)
287 myS = (Adaptor3d_SurfacePtr)&S;
297 if ((myusample < 2) ||
298 (myvsample < 2)) { Standard_OutOfRange::Raise(); }
302 mySphereUBTree.Nullify();
305 myInit = Standard_False;
308 inline static void fillParams(const TColStd_Array1OfReal& theKnots,
309 Standard_Integer theDegree,
310 Standard_Real theParMin,
311 Standard_Real theParMax,
312 Handle(TColStd_HArray1OfReal)& theParams,
313 Standard_Integer theSample)
315 NCollection_Vector<Standard_Real> aParams;
316 Standard_Integer i = 1;
317 Standard_Real aPrevPar = theParMin;
318 aParams.Append(aPrevPar);
319 //calculation the array of parametric points depending on the knots array variation and degree of given surface
320 for ( ; i < theKnots.Length() && theKnots(i) < (theParMax - Precision::PConfusion()); i++ )
322 if ( theKnots(i+1) < theParMin + Precision::PConfusion())
325 Standard_Real aStep = (theKnots(i+1) - theKnots(i))/Max(theDegree,2);
326 Standard_Integer k =1;
327 for( ; k <= theDegree ; k++)
329 Standard_Real aPar = theKnots(i) + k * aStep;
330 if(aPar > theParMax - Precision::PConfusion())
332 if(aPar > aPrevPar + Precision::PConfusion() )
334 aParams.Append(aPar);
340 aParams.Append(theParMax);
341 Standard_Integer nbPar = aParams.Length();
342 //in case of an insufficient number of points the grid will be built later
343 if (nbPar < theSample)
345 theParams = new TColStd_HArray1OfReal(1, nbPar );
346 for( i = 0; i < nbPar; i++)
347 theParams->SetValue(i+1,aParams(i));
350 void Extrema_GenExtPS::GetGridPoints( const Adaptor3d_Surface& theSurf)
352 //creation parametric points for BSpline and Bezier surfaces
353 //with taking into account of Degree and NbKnots of BSpline or Bezier geometry
354 if(theSurf.GetType() == GeomAbs_OffsetSurface)
355 GetGridPoints(theSurf.BasisSurface()->Surface());
356 //parametric points for BSpline surfaces
357 else if( theSurf.GetType() == GeomAbs_BSplineSurface)
359 Handle(Geom_BSplineSurface) aBspl = theSurf.BSpline();
362 TColStd_Array1OfReal aUKnots(1, aBspl->NbUKnots());
363 aBspl->UKnots( aUKnots);
364 TColStd_Array1OfReal aVKnots(1, aBspl->NbVKnots());
365 aBspl->VKnots( aVKnots);
366 fillParams(aUKnots,aBspl->UDegree(),myumin, myusup, myUParams, myusample);
367 fillParams(aVKnots,aBspl->VDegree(),myvmin, myvsup, myVParams, myvsample);
370 //calculation parametric points for Bezier surfaces
371 else if(theSurf.GetType() == GeomAbs_BezierSurface)
373 Handle(Geom_BezierSurface) aBezier = theSurf.Bezier();
377 TColStd_Array1OfReal aUKnots(1,2);
378 TColStd_Array1OfReal aVKnots(1,2);
379 aBezier->Bounds(aUKnots(1), aUKnots(2), aVKnots(1), aVKnots(2));
380 fillParams(aUKnots, aBezier->UDegree(), myumin, myusup, myUParams, myusample);
381 fillParams(aVKnots, aBezier->VDegree(), myvmin, myvsup, myVParams, myvsample);
384 //creation points for surfaces based on BSpline or Bezier curves
385 else if(theSurf.GetType() == GeomAbs_SurfaceOfRevolution ||
386 theSurf.GetType() == GeomAbs_SurfaceOfExtrusion)
388 Handle(TColStd_HArray1OfReal) anArrKnots;
389 Standard_Integer aDegree = 0;
390 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BSplineCurve)
392 Handle(Geom_BSplineCurve) aBspl = theSurf.BasisCurve()->Curve().BSpline();
395 anArrKnots = new TColStd_HArray1OfReal(1,aBspl->NbKnots());
396 aBspl->Knots( anArrKnots->ChangeArray1() );
397 aDegree = aBspl->Degree();
402 if(theSurf.BasisCurve()->Curve().GetType() == GeomAbs_BezierCurve)
404 Handle(Geom_BezierCurve) aBez = theSurf.BasisCurve()->Curve().Bezier();
407 anArrKnots = new TColStd_HArray1OfReal(1,2);
408 anArrKnots->SetValue(1, aBez->FirstParameter());
409 anArrKnots->SetValue(2, aBez->LastParameter());
410 aDegree = aBez->Degree();
414 if(anArrKnots.IsNull())
416 if( theSurf.GetType() == GeomAbs_SurfaceOfRevolution )
417 fillParams( anArrKnots->Array1(), aDegree, myvmin, myvsup, myVParams, myvsample);
419 fillParams( anArrKnots->Array1(), aDegree, myumin, myusup, myUParams, myusample);
421 //update the number of points in sample
422 if(!myUParams.IsNull())
423 myusample = myUParams->Length();
424 if( !myVParams.IsNull())
425 myvsample = myVParams->Length();
430 * This function computes the point on surface parameters on edge.
431 * if it coincides with theParam0 or theParam1, it is returned.
433 const Extrema_POnSurfParams& Extrema_GenExtPS::ComputeEdgeParameters
434 (const Standard_Boolean IsUEdge,
435 const Extrema_POnSurfParams &theParam0,
436 const Extrema_POnSurfParams &theParam1,
437 const gp_Pnt &thePoint,
438 const Standard_Real theDiffTol)
440 const Standard_Real aSqrDist01 =
441 theParam0.Value().SquareDistance(theParam1.Value());
443 if (aSqrDist01 <= theDiffTol)
445 // The points are confused. Get the first point and change its type.
450 const Standard_Real aDiffDist =
451 Abs(theParam0.GetSqrDistance() - theParam1.GetSqrDistance());
453 if (aDiffDist >= aSqrDist01 - theDiffTol)
455 // The shortest distance is one of the nodes.
456 if (theParam0.GetSqrDistance() > theParam1.GetSqrDistance())
458 // The shortest distance is the point 1.
463 // The shortest distance is the point 0.
469 // The shortest distance is inside the edge.
470 gp_XYZ aPoP(thePoint.XYZ().Subtracted(theParam0.Value().XYZ()));
471 gp_XYZ aPoP1(theParam1.Value().XYZ().Subtracted(theParam0.Value().XYZ()));
472 Standard_Real aRatio = aPoP.Dot(aPoP1)/aSqrDist01;
476 theParam0.Parameter(aU[0], aV[0]);
477 theParam1.Parameter(aU[1], aV[1]);
479 Standard_Real aUPar = aU[0];
480 Standard_Real aVPar = aV[0];
484 aUPar += aRatio*(aU[1] - aU[0]);
488 aVPar += aRatio*(aV[1] - aV[0]);
491 myGridParam.SetParameters(aUPar, aVPar, myS->Value(aUPar, aVPar));
492 Standard_Integer anIndices[2];
494 theParam0.GetIndices(anIndices[0], anIndices[1]);
495 myGridParam.SetElementType(IsUEdge ? Extrema_UIsoEdge : Extrema_VIsoEdge);
496 myGridParam.SetSqrDistance(thePoint.SquareDistance(myGridParam.Value()));
497 myGridParam.SetIndices(anIndices[0], anIndices[1]);
503 void Extrema_GenExtPS::BuildGrid(const gp_Pnt &thePoint)
505 Standard_Integer NoU, NoV;
507 //if grid was already built skip its creation
509 //build parametric grid in case of a complex surface geometry (BSpline and Bezier surfaces)
512 //build grid in other cases
513 if( myUParams.IsNull() )
515 Standard_Real PasU = myusup - myumin;
516 Standard_Real U0 = PasU / myusample / 100.;
517 PasU = (PasU - U0) / (myusample - 1);
519 myUParams = new TColStd_HArray1OfReal(1,myusample );
520 Standard_Integer NoU;
521 Standard_Real U = U0;
522 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
523 myUParams->SetValue(NoU, U);
526 if( myVParams.IsNull())
528 Standard_Real PasV = myvsup - myvmin;
529 Standard_Real V0 = PasV / myvsample / 100.;
530 PasV = (PasV - V0) / (myvsample - 1);
533 myVParams = new TColStd_HArray1OfReal(1,myvsample );
534 Standard_Integer NoV;
535 Standard_Real V = V0;
537 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
538 myVParams->SetValue(NoV, V);
541 //If flag was changed and extrema not reinitialized Extrema would fail
542 myPoints = new Extrema_HArray2OfPOnSurfParams
543 (0, myusample + 1, 0, myvsample + 1);
544 // Calculation of distances
546 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
547 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
548 gp_Pnt aP1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
549 Extrema_POnSurfParams aParam
550 (myUParams->Value(NoU), myVParams->Value(NoV), aP1);
552 aParam.SetElementType(Extrema_Node);
553 aParam.SetIndices(NoU, NoV);
554 myPoints->SetValue(NoU, NoV, aParam);
559 new Extrema_HArray2OfPOnSurfParams(0, myusample, 0, myvsample);
562 new Extrema_HArray2OfPOnSurfParams(1, myusample - 1, 1, myvsample);
564 new Extrema_HArray2OfPOnSurfParams(1, myusample, 1, myvsample - 1);
566 // Fill boundary with negative square distance.
567 // It is used for computation of Maximum.
568 for (NoV = 0; NoV <= myvsample + 1; NoV++) {
569 myPoints->ChangeValue(0, NoV).SetSqrDistance(-1.);
570 myPoints->ChangeValue(myusample + 1, NoV).SetSqrDistance(-1.);
573 for (NoU = 1; NoU <= myusample; NoU++) {
574 myPoints->ChangeValue(NoU, 0).SetSqrDistance(-1.);
575 myPoints->ChangeValue(NoU, myvsample + 1).SetSqrDistance(-1.);
578 myInit = Standard_True;
581 // Compute distances to mesh.
582 // Step 1. Compute distances to nodes.
583 for ( NoU = 1 ; NoU <= myusample; NoU++ ) {
584 for ( NoV = 1 ; NoV <= myvsample; NoV++) {
585 Extrema_POnSurfParams &aParam = myPoints->ChangeValue(NoU, NoV);
587 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
591 // For search of minimum compute distances to mesh.
592 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
594 // This is the tolerance of difference of squared values.
595 // No need to set it too small.
596 const Standard_Real aDiffTol = mytolu + mytolv;
598 // Step 2. Compute distances to edges.
599 // Assume UEdge(i, j) = { Point(i, j); Point(i + 1, j ) }
600 // Assume VEdge(i, j) = { Point(i, j); Point(i, j + 1) }
601 for ( NoU = 1 ; NoU <= myusample; NoU++ )
603 for ( NoV = 1 ; NoV <= myvsample; NoV++)
605 const Extrema_POnSurfParams &aParam0 = myPoints->Value(NoU, NoV);
609 // Compute parameters to UEdge.
610 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU + 1, NoV);
611 const Extrema_POnSurfParams &anEdgeParam = ComputeEdgeParameters(Standard_True, aParam0, aParam1, thePoint, aDiffTol);
613 myUEdgePntParams->SetValue(NoU, NoV, anEdgeParam);
618 // Compute parameters to VEdge.
619 const Extrema_POnSurfParams &aParam1 = myPoints->Value(NoU, NoV + 1);
620 const Extrema_POnSurfParams &anEdgeParam = ComputeEdgeParameters(Standard_False, aParam0, aParam1, thePoint, aDiffTol);
622 myVEdgePntParams->SetValue(NoU, NoV, anEdgeParam);
627 // Step 3. Compute distances to faces.
628 // Assume myFacePntParams(i, j) =
629 // { Point(i, j); Point(i + 1, j); Point(i + 1, j + 1); Point(i, j + 1) }
631 // { UEdge(i, j); VEdge(i + 1, j); UEdge(i, j + 1); VEdge(i, j) }
632 Standard_Real aSqrDist01;
633 Standard_Real aDiffDist;
634 Standard_Boolean isOut;
636 for ( NoU = 1 ; NoU < myusample; NoU++ ) {
637 for ( NoV = 1 ; NoV < myvsample; NoV++) {
638 const Extrema_POnSurfParams &aUE0 = myUEdgePntParams->Value(NoU, NoV);
639 const Extrema_POnSurfParams &aUE1 = myUEdgePntParams->Value(NoU, NoV+1);
640 const Extrema_POnSurfParams &aVE0 = myVEdgePntParams->Value(NoU, NoV);
641 const Extrema_POnSurfParams &aVE1 = myVEdgePntParams->Value(NoU+1, NoV);
643 aSqrDist01 = aUE0.Value().SquareDistance(aUE1.Value());
644 aDiffDist = Abs(aUE0.GetSqrDistance() - aUE1.GetSqrDistance());
645 isOut = Standard_False;
647 if (aDiffDist >= aSqrDist01 - aDiffTol) {
648 // The projection is outside the face.
649 isOut = Standard_True;
651 aSqrDist01 = aVE0.Value().SquareDistance(aVE1.Value());
652 aDiffDist = Abs(aVE0.GetSqrDistance() - aVE1.GetSqrDistance());
654 if (aDiffDist >= aSqrDist01 - aDiffTol) {
655 // The projection is outside the face.
656 isOut = Standard_True;
661 // Get the closest point on an edge.
662 const Extrema_POnSurfParams &aUEMin =
663 aUE0.GetSqrDistance() < aUE1.GetSqrDistance() ? aUE0 : aUE1;
664 const Extrema_POnSurfParams &aVEMin =
665 aVE0.GetSqrDistance() < aVE1.GetSqrDistance() ? aVE0 : aVE1;
666 const Extrema_POnSurfParams &aEMin =
667 aUEMin.GetSqrDistance() < aVEMin.GetSqrDistance() ? aUEMin : aVEMin;
669 myFacePntParams->SetValue(NoU, NoV, aEMin);
671 // Find closest point inside the face.
677 // Compute U parameter.
678 aUE0.Parameter(aU[0], aV[0]);
679 aUE1.Parameter(aU[1], aV[1]);
680 aUPar = 0.5*(aU[0] + aU[1]);
681 // Compute V parameter.
682 aVE0.Parameter(aU[0], aV[0]);
683 aVE1.Parameter(aU[1], aV[1]);
684 aVPar = 0.5*(aV[0] + aV[1]);
686 Extrema_POnSurfParams aParam(aUPar, aVPar, myS->Value(aUPar, aVPar));
688 aParam.SetElementType(Extrema_Face);
689 aParam.SetSqrDistance(thePoint.SquareDistance(aParam.Value()));
690 aParam.SetIndices(NoU, NoV);
691 myFacePntParams->SetValue(NoU, NoV, aParam);
696 // Fill boundary with RealLast square distance.
697 for (NoV = 0; NoV <= myvsample; NoV++) {
698 myFacePntParams->ChangeValue(0, NoV).SetSqrDistance(RealLast());
699 myFacePntParams->ChangeValue(myusample, NoV).SetSqrDistance(RealLast());
702 for (NoU = 1; NoU < myusample; NoU++) {
703 myFacePntParams->ChangeValue(NoU, 0).SetSqrDistance(RealLast());
704 myFacePntParams->ChangeValue(NoU, myvsample).SetSqrDistance(RealLast());
709 // Parameterisation of the sample
710 void Extrema_GenExtPS::BuildTree()
712 // if tree already exists, assume it is already correctly filled
713 if ( ! mySphereUBTree.IsNull() )
716 if (myS->GetType() == GeomAbs_BSplineSurface) {
717 Handle(Geom_BSplineSurface) aBspl = myS->BSpline();
718 Standard_Integer aUValue = aBspl->UDegree() * aBspl->NbUKnots();
719 Standard_Integer aVValue = aBspl->VDegree() * aBspl->NbVKnots();
720 if (aUValue > myusample)
722 if (aVValue > myvsample)
726 Standard_Real PasU = myusup - myumin;
727 Standard_Real PasV = myvsup - myvmin;
728 Standard_Real U0 = PasU / myusample / 100.;
729 Standard_Real V0 = PasV / myvsample / 100.;
731 PasU = (PasU - U0) / (myusample - 1);
732 PasV = (PasV - V0) / (myvsample - 1);
736 //build grid of parametric points
737 myUParams = new TColStd_HArray1OfReal(1,myusample );
738 myVParams = new TColStd_HArray1OfReal(1,myvsample );
739 Standard_Integer NoU, NoV;
740 Standard_Real U = U0, V = V0;
741 for ( NoU = 1 ; NoU <= myusample; NoU++, U += PasU)
742 myUParams->SetValue(NoU, U);
743 for ( NoV = 1, V = V0; NoV <= myvsample; NoV++, V += PasV)
744 myVParams->SetValue(NoV, V);
746 // Calculation of distances
747 mySphereUBTree = new Extrema_UBTreeOfSphere;
748 Extrema_UBTreeFillerOfSphere aFiller(*mySphereUBTree);
749 Standard_Integer i = 0;
751 mySphereArray = new Bnd_HArray1OfSphere(0, myusample * myvsample);
753 for ( NoU = 1; NoU <= myusample; NoU++ ) {
754 for ( NoV = 1; NoV <= myvsample; NoV++) {
755 P1 = myS->Value(myUParams->Value(NoU), myVParams->Value(NoV));
756 Bnd_Sphere aSph(P1.XYZ(), 0/*mytolu < mytolv ? mytolu : mytolv*/, NoU, NoV);
757 aFiller.Add(i, aSph);
758 mySphereArray->SetValue( i, aSph );
765 void Extrema_GenExtPS::FindSolution(const gp_Pnt& /*P*/,
766 const Extrema_POnSurfParams &theParams)
768 math_Vector Tol(1,2);
772 math_Vector UV(1, 2);
773 theParams.Parameter(UV(1), UV(2));
775 math_Vector UVinf(1,2), UVsup(1,2);
781 const Standard_Integer aNbMaxIter = 100;
782 math_FunctionSetRoot S (myF, UV, Tol, UVinf, UVsup, aNbMaxIter);
784 myDone = Standard_True;
787 void Extrema_GenExtPS::SetFlag(const Extrema_ExtFlag F)
792 void Extrema_GenExtPS::SetAlgo(const Extrema_ExtAlgo A)
795 myInit = Standard_False;
800 void Extrema_GenExtPS::Perform(const gp_Pnt& P)
802 myDone = Standard_False;
805 if(myAlgo == Extrema_ExtAlgo_Grad)
808 Standard_Integer NoU,NoV;
810 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
812 Extrema_ElementType anElemType;
815 Standard_Integer iU2;
816 Standard_Integer iV2;
817 Standard_Boolean isMin;
820 for (NoU = 1; NoU < myusample; NoU++) {
821 for (NoV = 1; NoV < myvsample; NoV++) {
822 const Extrema_POnSurfParams &aParam =
823 myFacePntParams->Value(NoU, NoV);
825 isMin = Standard_False;
826 anElemType = aParam.GetElementType();
828 if (anElemType == Extrema_Face) {
829 isMin = Standard_True;
831 // Check if it is a boundary edge or corner vertex.
832 aParam.GetIndices(iU, iV);
834 if (anElemType == Extrema_UIsoEdge) {
835 isMin = (iV == 1 || iV == myvsample);
836 } else if (anElemType == Extrema_VIsoEdge) {
837 isMin = (iU == 1 || iU == myusample);
838 } else if (anElemType == Extrema_Node) {
839 isMin = (iU == 1 || iU == myusample) &&
840 (iV == 1 || iV == myvsample);
844 // This is a middle element.
845 if (anElemType == Extrema_UIsoEdge ||
846 (anElemType == Extrema_Node && (iU == 1 || iU == myusample))) {
847 // Check the down face.
848 const Extrema_POnSurfParams &aDownParam =
849 myFacePntParams->Value(NoU, NoV - 1);
851 if (aDownParam.GetElementType() == anElemType) {
852 aDownParam.GetIndices(iU2, iV2);
853 isMin = (iU == iU2 && iV == iV2);
855 } else if (anElemType == Extrema_VIsoEdge ||
856 (anElemType == Extrema_Node && (iV == 1 || iV == myvsample))) {
857 // Check the right face.
858 const Extrema_POnSurfParams &aRightParam =
859 myFacePntParams->Value(NoU - 1, NoV);
861 if (aRightParam.GetElementType() == anElemType) {
862 aRightParam.GetIndices(iU2, iV2);
863 isMin = (iU == iU2 && iV == iV2);
865 } else if (iU == NoU && iV == NoV) {
866 // Check the lower-left node. For this purpose it is necessary
867 // to check lower-left, lower and left faces.
868 isMin = Standard_True;
870 const Extrema_POnSurfParams *anOtherParam[3] =
871 { &myFacePntParams->Value(NoU, NoV - 1), // Down
872 &myFacePntParams->Value(NoU - 1, NoV - 1), // Lower-left
873 &myFacePntParams->Value(NoU - 1, NoV) }; // Left
875 for (i = 0; i < 3 && isMin; i++) {
876 if (anOtherParam[i]->GetElementType() == Extrema_Node) {
877 anOtherParam[i]->GetIndices(iU2, iV2);
878 isMin = (iU == iU2 && iV == iV2);
880 isMin = Standard_False;
888 FindSolution(P, aParam);
894 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
898 for (NoU = 1; NoU <= myusample; NoU++) {
899 for (NoV = 1; NoV <= myvsample; NoV++) {
900 Dist = myPoints->Value(NoU, NoV).GetSqrDistance();
901 if ((myPoints->Value(NoU-1,NoV-1).GetSqrDistance() <= Dist) &&
902 (myPoints->Value(NoU-1,NoV ).GetSqrDistance() <= Dist) &&
903 (myPoints->Value(NoU-1,NoV+1).GetSqrDistance() <= Dist) &&
904 (myPoints->Value(NoU ,NoV-1).GetSqrDistance() <= Dist) &&
905 (myPoints->Value(NoU ,NoV+1).GetSqrDistance() <= Dist) &&
906 (myPoints->Value(NoU+1,NoV-1).GetSqrDistance() <= Dist) &&
907 (myPoints->Value(NoU+1,NoV ).GetSqrDistance() <= Dist) &&
908 (myPoints->Value(NoU+1,NoV+1).GetSqrDistance() <= Dist)) {
910 FindSolution(P, myPoints->Value(NoU, NoV));
919 if(myFlag == Extrema_ExtFlag_MIN || myFlag == Extrema_ExtFlag_MINMAX)
921 Bnd_Sphere aSol = mySphereArray->Value(0);
922 Bnd_SphereUBTreeSelectorMin aSelector(mySphereArray, aSol);
923 //aSelector.SetMaxDist( RealLast() );
924 aSelector.DefineCheckPoint( P );
925 mySphereUBTree->Select( aSelector );
926 //TODO: check if no solution in binary tree
927 Bnd_Sphere& aSph = aSelector.Sphere();
928 Standard_Real aU = myUParams->Value(aSph.U());
929 Standard_Real aV = myVParams->Value(aSph.V());
930 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
932 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
933 aParams.SetIndices(aSph.U(), aSph.V());
934 FindSolution(P, aParams);
936 if(myFlag == Extrema_ExtFlag_MAX || myFlag == Extrema_ExtFlag_MINMAX)
938 Bnd_Sphere aSol = mySphereArray->Value(0);
939 Bnd_SphereUBTreeSelectorMax aSelector(mySphereArray, aSol);
940 //aSelector.SetMaxDist( RealLast() );
941 aSelector.DefineCheckPoint( P );
942 mySphereUBTree->Select( aSelector );
943 //TODO: check if no solution in binary tree
944 Bnd_Sphere& aSph = aSelector.Sphere();
945 Standard_Real aU = myUParams->Value(aSph.U());
946 Standard_Real aV = myVParams->Value(aSph.V());
947 Extrema_POnSurfParams aParams(aU, aV, myS->Value(aU, aV));
948 aParams.SetSqrDistance(P.SquareDistance(aParams.Value()));
949 aParams.SetIndices(aSph.U(), aSph.V());
951 FindSolution(P, aParams);
955 //=============================================================================
957 Standard_Boolean Extrema_GenExtPS::IsDone () const { return myDone; }
958 //=============================================================================
960 Standard_Integer Extrema_GenExtPS::NbExt () const
962 if (!IsDone()) { StdFail_NotDone::Raise(); }
965 //=============================================================================
967 Standard_Real Extrema_GenExtPS::SquareDistance (const Standard_Integer N) const
969 if (!IsDone()) { StdFail_NotDone::Raise(); }
970 return myF.SquareDistance(N);
972 //=============================================================================
974 const Extrema_POnSurf& Extrema_GenExtPS::Point (const Standard_Integer N) const
976 if (!IsDone()) { StdFail_NotDone::Raise(); }
979 //=============================================================================