Warning, /include/opencascade/Extrema_FuncExtPC.gxx is written in an unsupported language. File is not indexed.
0001 // Copyright (c) 1995-1999 Matra Datavision
0002 // Copyright (c) 1999-2014 OPEN CASCADE SAS
0003 //
0004 // This file is part of Open CASCADE Technology software library.
0005 //
0006 // This library is free software; you can redistribute it and/or modify it under
0007 // the terms of the GNU Lesser General Public License version 2.1 as published
0008 // by the Free Software Foundation, with special exception defined in the file
0009 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0010 // distribution for complete text of the license and disclaimer of any warranty.
0011 //
0012 // Alternatively, this file may be used under the terms of Open CASCADE
0013 // commercial license or contractual agreement.
0014
0015 #include <Standard_TypeMismatch.hxx>
0016 #include <Precision.hxx>
0017 static const Standard_Real TolFactor = 1.e-12;
0018 static const Standard_Real MinTol = 1.e-20;
0019 static const Standard_Real MinStep = 1e-7;
0020
0021 static const Standard_Integer MaxOrder = 3;
0022
0023
0024
0025 /*-----------------------------------------------------------------------------
0026 Fonction permettant de rechercher une distance extremale entre un point P et
0027 une courbe C (en partant d'un point approche C(u0)).
0028 Cette classe herite de math_FunctionWithDerivative et est utilisee par
0029 les algorithmes math_FunctionRoot et math_FunctionRoots.
0030 Si on note D1c et D2c les derivees premiere et seconde:
0031 { F(u) = (C(u)-P).D1c(u)/ ||Du||}
0032 { DF(u) = ||Du|| + (C(u)-P).D2c(u)/||Du|| - F(u)*Duu*Du/||Du||**2
0033
0034
0035 { F(u) = (C(u)-P).D1c(u) }
0036 { DF(u) = D1c(u).D1c(u) + (C(u)-P).D2c(u)
0037 = ||D1c(u)|| ** 2 + (C(u)-P).D2c(u) }
0038 ----------------------------------------------------------------------------*/
0039
0040 Standard_Real Extrema_FuncExtPC::SearchOfTolerance()
0041 {
0042 const Standard_Integer NPoint = 10;
0043 const Standard_Real aStep = (myUsupremum - myUinfium)/(Standard_Real)NPoint;
0044
0045 Standard_Integer aNum = 0;
0046 Standard_Real aMax = -Precision::Infinite(); //Maximum value of 1st derivative
0047 //(it is computed with using NPoint point)
0048
0049 do
0050 {
0051 Standard_Real u = myUinfium + aNum*aStep; //parameter for every point
0052 if(u > myUsupremum)
0053 u = myUsupremum;
0054
0055 Pnt Ptemp; //empty point (is not used below)
0056 Vec VDer; // 1st derivative vector
0057 Tool::D1(*((Curve*)myC), u, Ptemp, VDer);
0058
0059 if(Precision::IsInfinite(VDer.X()) || Precision::IsInfinite(VDer.Y()))
0060 {
0061 continue;
0062 }
0063
0064 Standard_Real vm = VDer.Magnitude();
0065 if(vm > aMax)
0066 aMax = vm;
0067 }
0068 while(++aNum < NPoint+1);
0069
0070 return Max(aMax*TolFactor,MinTol);
0071
0072 }
0073
0074 //=============================================================================
0075
0076 Extrema_FuncExtPC::Extrema_FuncExtPC():
0077 myU(0.),
0078 myD1f(0.)
0079 {
0080 myPinit = Standard_False;
0081 myCinit = Standard_False;
0082 myD1Init = Standard_False;
0083
0084 SubIntervalInitialize(0.0,0.0);
0085 myMaxDerivOrder = 0;
0086 myTol=MinTol;
0087 }
0088
0089 //=============================================================================
0090
0091 Extrema_FuncExtPC::Extrema_FuncExtPC (const Pnt& P,
0092 const Curve& C): myU(0.), myD1f(0.)
0093 {
0094 myP = P;
0095 myC = (Standard_Address)&C;
0096 myPinit = Standard_True;
0097 myCinit = Standard_True;
0098 myD1Init = Standard_False;
0099
0100 SubIntervalInitialize(Tool::FirstParameter(*((Curve*)myC)),
0101 Tool::LastParameter(*((Curve*)myC)));
0102
0103 switch(Tool::GetType(*((Curve*)myC)))
0104 {
0105 case GeomAbs_BezierCurve:
0106 case GeomAbs_BSplineCurve:
0107 case GeomAbs_OffsetCurve:
0108 case GeomAbs_OtherCurve:
0109 myMaxDerivOrder = MaxOrder;
0110 myTol = SearchOfTolerance();
0111 break;
0112 default:
0113 myMaxDerivOrder = 0;
0114 myTol=MinTol;
0115 break;
0116 }
0117 }
0118 //=============================================================================
0119
0120 void Extrema_FuncExtPC::Initialize(const Curve& C)
0121 {
0122 myC = (Standard_Address)&C;
0123 myCinit = Standard_True;
0124 myPoint.Clear();
0125 mySqDist.Clear();
0126 myIsMin.Clear();
0127
0128 SubIntervalInitialize(Tool::FirstParameter(*((Curve*)myC)),
0129 Tool::LastParameter(*((Curve*)myC)));
0130
0131 switch(Tool::GetType(*((Curve*)myC)))
0132 {
0133 case GeomAbs_BezierCurve:
0134 case GeomAbs_BSplineCurve:
0135 case GeomAbs_OffsetCurve:
0136 case GeomAbs_OtherCurve:
0137 myMaxDerivOrder = MaxOrder;
0138 myTol = SearchOfTolerance();
0139 break;
0140 default:
0141 myMaxDerivOrder = 0;
0142 myTol=MinTol;
0143 break;
0144 }
0145 }
0146
0147 //=============================================================================
0148
0149 void Extrema_FuncExtPC::SetPoint(const Pnt& P)
0150 {
0151 myP = P;
0152 myPinit = Standard_True;
0153 myPoint.Clear();
0154 mySqDist.Clear();
0155 myIsMin.Clear();
0156 }
0157
0158 //=============================================================================
0159
0160
0161 Standard_Boolean Extrema_FuncExtPC::Value (const Standard_Real U, Standard_Real& F)
0162 {
0163 if (!myPinit || !myCinit)
0164 throw Standard_TypeMismatch("No init");
0165
0166 myU = U;
0167 Vec D1c;
0168 Tool::D1(*((Curve*)myC),myU,myPc,D1c);
0169
0170 if(Precision::IsInfinite(D1c.X()) || Precision::IsInfinite(D1c.Y()))
0171 {
0172 F = Precision::Infinite();
0173 return Standard_False;
0174 }
0175
0176 Standard_Real Ndu = D1c.Magnitude();
0177
0178 if(myMaxDerivOrder != 0)
0179 {
0180 if (Ndu <= myTol) // Cas Singulier (PMN 22/04/1998)
0181 {
0182 const Standard_Real DivisionFactor = 1.e-3;
0183 Standard_Real du;
0184 if((myUsupremum >= RealLast()) || (myUinfium <= RealFirst()))
0185 du = 0.0;
0186 else
0187 du = myUsupremum-myUinfium;
0188
0189 const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
0190 //Derivative is approximated by Taylor-series
0191
0192 Standard_Integer n = 1; //Derivative order
0193 Vec V;
0194 Standard_Boolean IsDeriveFound;
0195
0196 do
0197 {
0198 V = Tool::DN(*((Curve*)myC),myU,++n);
0199 Ndu = V.Magnitude();
0200 IsDeriveFound = (Ndu > myTol);
0201 }
0202 while(!IsDeriveFound && n < myMaxDerivOrder);
0203
0204 if(IsDeriveFound)
0205 {
0206 Standard_Real u;
0207
0208 if(myU-myUinfium < aDelta)
0209 u = myU+aDelta;
0210 else
0211 u = myU-aDelta;
0212
0213 Pnt P1, P2;
0214 Tool::D0(*((Curve*)myC),Min(myU, u),P1);
0215 Tool::D0(*((Curve*)myC),Max(myU, u),P2);
0216
0217 Vec V1(P1,P2);
0218 Standard_Real aDirFactor = V.Dot(V1);
0219
0220 if(aDirFactor < 0.0)
0221 D1c = -V;
0222 else
0223 D1c = V;
0224 }//if(IsDeriveFound)
0225 else
0226 {
0227 //Derivative is approximated by three points
0228
0229 Pnt Ptemp; //(0,0,0)-coordinate
0230 Pnt P1, P2, P3;
0231 Standard_Boolean IsParameterGrown;
0232
0233 if(myU-myUinfium < 2*aDelta)
0234 {
0235 Tool::D0(*((Curve*)myC),myU,P1);
0236 Tool::D0(*((Curve*)myC),myU+aDelta,P2);
0237 Tool::D0(*((Curve*)myC),myU+2*aDelta,P3);
0238 IsParameterGrown = Standard_True;
0239 }
0240 else
0241 {
0242 Tool::D0(*((Curve*)myC),myU-2*aDelta,P1);
0243 Tool::D0(*((Curve*)myC),myU-aDelta,P2);
0244 Tool::D0(*((Curve*)myC),myU,P3);
0245 IsParameterGrown = Standard_False;
0246 }
0247
0248 Vec V1(Ptemp,P1), V2(Ptemp,P2), V3(Ptemp,P3);
0249
0250 if(IsParameterGrown)
0251 D1c=-3*V1+4*V2-V3;
0252 else
0253 D1c=V1-4*V2+3*V3;
0254 }
0255 Ndu = D1c.Magnitude();
0256 }//(if (Ndu <= myTol)) condition
0257 }//if(myMaxDerivOrder != 0)
0258
0259 if (Ndu <= MinTol)
0260 {
0261 //Warning: 1st derivative is equal to zero!
0262 return Standard_False;
0263 }
0264
0265 Vec PPc (myP,myPc);
0266 F = PPc.Dot(D1c)/Ndu;
0267 return Standard_True;
0268 }
0269
0270 //=============================================================================
0271
0272 Standard_Boolean Extrema_FuncExtPC::Derivative (const Standard_Real U, Standard_Real& D1f)
0273 {
0274 if (!myPinit || !myCinit) throw Standard_TypeMismatch();
0275 Standard_Real F;
0276 return Values(U,F,D1f); /* on fait appel a Values pour simplifier la
0277 sauvegarde de l'etat. */
0278 }
0279 //=============================================================================
0280
0281 Standard_Boolean Extrema_FuncExtPC::Values (const Standard_Real U,
0282 Standard_Real& F,
0283 Standard_Real& D1f)
0284 {
0285 if (!myPinit || !myCinit)
0286 throw Standard_TypeMismatch("No init");
0287
0288 Pnt myPc_old = myPc, myP_old = myP;
0289
0290 if(Value(U,F) == Standard_False)
0291 {
0292 //Warning: No function value found!;
0293
0294 myD1Init = Standard_False;
0295 return Standard_False;
0296 }
0297
0298 myU = U;
0299 myPc = myPc_old;
0300 myP = myP_old;
0301
0302 Vec D1c,D2c;
0303 Tool::D2(*((Curve*)myC),myU,myPc,D1c,D2c);
0304
0305 Standard_Real Ndu = D1c.Magnitude();
0306 if (Ndu <= myTol) // Cas Singulier (PMN 22/04/1998)
0307 {
0308 //Derivative is approximated by three points
0309
0310 //Attention: aDelta value must be greater than same value for "Value(...)"
0311 // function to avoid of points' collisions.
0312 const Standard_Real DivisionFactor = 0.01;
0313 Standard_Real du;
0314 if((myUsupremum >= RealLast()) || (myUinfium <= RealFirst()))
0315 du = 0.0;
0316 else
0317 du = myUsupremum-myUinfium;
0318
0319 const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
0320
0321 Standard_Real F1, F2, F3;
0322
0323 if(myU-myUinfium < 2*aDelta)
0324 {
0325 F1=F;
0326 //const Standard_Real U1 = myU;
0327 const Standard_Real U2 = myU + aDelta;
0328 const Standard_Real U3 = myU + aDelta * 2.0;
0329
0330 if(!((Value(U2,F2)) && (Value(U3,F3))))
0331 {
0332 //There are many points close to singularity points and
0333 //which have zero-derivative. Try to decrease aDelta variable's value.
0334
0335 myD1Init = Standard_False;
0336 return Standard_False;
0337 }
0338
0339 //After calling of Value(...) function variable myU will be redeterminated.
0340 //So we must return it previous value.
0341 D1f=(-3*F1+4*F2-F3)/(2.0*aDelta);
0342 }
0343 else
0344 {
0345 F3 = F;
0346 const Standard_Real U1 = myU - aDelta * 2.0;
0347 const Standard_Real U2 = myU - aDelta;
0348 //const Standard_Real U3 = myU;
0349
0350 if(!((Value(U2,F2)) && (Value(U1,F1))))
0351 {
0352 //There are many points close to singularity points and
0353 //which have zero-derivative. Try to decrease aDelta variable's value.
0354 myD1Init = Standard_False;
0355 return Standard_False;
0356 }
0357 //After calling of Value(...) function variable myU will be redeterminated.
0358 //So we must return it previous value.
0359 D1f=(F1-4*F2+3*F3)/(2.0*aDelta);
0360 }
0361 myU = U;
0362 myPc = myPc_old;
0363 myP = myP_old;
0364 }
0365 else
0366 {
0367 Vec PPc (myP,myPc);
0368 D1f = Ndu + (PPc.Dot(D2c)/Ndu) - F*(D1c.Dot(D2c))/(Ndu*Ndu);
0369 }
0370
0371 myD1f = D1f;
0372
0373 myD1Init = Standard_True;
0374 return Standard_True;
0375 }
0376 //=============================================================================
0377
0378 Standard_Integer Extrema_FuncExtPC::GetStateNumber ()
0379 {
0380 if (!myPinit || !myCinit) throw Standard_TypeMismatch();
0381 mySqDist.Append(myPc.SquareDistance(myP));
0382
0383 // It is necessary to always compute myD1f.
0384 myD1Init = Standard_True;
0385 Standard_Real FF, DD;
0386 Values(myU, FF, DD);
0387
0388 Standard_Integer IntVal = 0;
0389 if (myD1f > 0.0)
0390 {
0391 IntVal = 1;
0392 }
0393
0394 myIsMin.Append(IntVal);
0395 myPoint.Append(POnC(myU,myPc));
0396 return 0;
0397 }
0398 //=============================================================================
0399
0400 Standard_Integer Extrema_FuncExtPC::NbExt () const { return mySqDist.Length(); }
0401 //=============================================================================
0402
0403 Standard_Real Extrema_FuncExtPC::SquareDistance (const Standard_Integer N) const
0404 {
0405 if (!myPinit || !myCinit) throw Standard_TypeMismatch();
0406 return mySqDist.Value(N);
0407 }
0408 //=============================================================================
0409 Standard_Boolean Extrema_FuncExtPC::IsMin (const Standard_Integer N) const
0410 {
0411 if (!myPinit || !myCinit) throw Standard_TypeMismatch();
0412 return (myIsMin.Value(N) == 1);
0413 }
0414 //=============================================================================
0415 const POnC & Extrema_FuncExtPC::Point (const Standard_Integer N) const
0416 {
0417 if (!myPinit || !myCinit) throw Standard_TypeMismatch();
0418 return myPoint.Value(N);
0419 }
0420 //=============================================================================
0421
0422 void Extrema_FuncExtPC::SubIntervalInitialize(const Standard_Real theUfirst, const Standard_Real theUlast)
0423 {
0424 myUinfium = theUfirst;
0425 myUsupremum = theUlast;
0426 }