1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-04 13:13:25 +03:00
occt/src/Extrema/Extrema_FuncExtCC.gxx
abv d5f74e42d6 0024624: Lost word in license statement in source files
License statement text corrected; compiler warnings caused by Bison 2.41 disabled for MSVC; a few other compiler warnings on 54-bit Windows eliminated by appropriate type cast
Wrong license statements corrected in several files.
Copyright and license statements added in XSD and GLSL files.
Copyright year updated in some files.
Obsolete documentation files removed from DrawResources.
2014-02-20 16:15:17 +04:00

720 lines
20 KiB
Plaintext

// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
//Modified by MPS : 21-05-97 PRO 7598
// Le nombre de solutions rendu est mySqDist.Length() et non
// mySqDist.Length()/2
// ajout des valeurs absolues dans le test d'orthogonalite de
// GetStateNumber()
/*-----------------------------------------------------------------------------
Fonctions permettant de rechercher une distance extremale entre 2 courbes
C1 et C2 (en partant de points approches C1(u0) et C2(v0)).
Cette classe herite de math_FunctionSetWithDerivatives et est utilisee par
l'algorithme math_FunctionSetRoot.
Si on note Du et Dv, les derivees en u et v, les 2 fonctions a annuler sont:
{ F1(u,v) = (C2(v)-C1(u)).Du(u)/||Du|| }
{ F2(u,v) = (C2(v)-C1(u)).Dv(v)||Dv|| }
Si on note Duu et Dvv, les derivees secondes de C1 et C2, les derivees de F1
et F2 sont egales a:
{ Duf1(u,v) = -||Du|| + C1C2.Duu/||Du||- F1(u,v)*Duu*Du/||Du||**2
{ Dvf1(u,v) = Dv.Du/||Du||
{ Duf2(u,v) = -Du.Dv/||Dv||
{ Dvf2(u,v) = ||Dv|| + C2C1.Dvv/||Dv||- F2(u,v)*Dv*Dvv/||Dv||**2
----------------------------------------------------------------------------*/
#include <Precision.hxx>
static const Standard_Real MinTol = 1.e-20;
static const Standard_Real TolFactor = 1.e-12;
static const Standard_Real MinStep = 1e-7;
static const Standard_Integer MaxOrder = 3;
//=============================================================================
Standard_Real Extrema_FuncExtCC::SearchOfTolerance(const Standard_Address C)
{
const Standard_Integer NPoint = 10;
Standard_Real aStartParam, anEndParam;
if(C==myC1)
{
aStartParam = myUinfium;
anEndParam = myUsupremum;
}
else if(C==myC2)
{
aStartParam = myVinfium;
anEndParam = myVsupremum;
}
else
{
//Warning: No curve for tolerance computing!
return MinTol;
}
const Standard_Real aStep = (anEndParam - aStartParam)/(Standard_Real)NPoint;
Standard_Integer aNum = 0;
Standard_Real aMax = -Precision::Infinite(); //Maximum value of 1st derivative
//(it is computed with using NPoint point)
do
{
Standard_Real u = aStartParam + aNum*aStep; //parameter for every point
if(u > anEndParam)
u = anEndParam;
Pnt Ptemp; //empty point (is not used below)
Vec VDer; // 1st derivative vector
Tool1::D1(*((Curve1*)C), u, Ptemp, VDer);
Standard_Real vm = VDer.Magnitude();
if(vm > aMax)
aMax = vm;
}
while(++aNum < NPoint+1);
return Max(aMax*TolFactor,MinTol);
}
//=============================================================================
Extrema_FuncExtCC::Extrema_FuncExtCC(const Standard_Real thetol) : myC1 (0), myC2 (0), myTol (thetol)
{
math_Vector V1(1,2), V2(1,2);
V1(1) = 0.0;
V2(1) = 0.0;
V1(2) = 0.0;
V2(2) = 0.0;
SubIntervalInitialize(V1, V2);
myMaxDerivOrderC1 = 0;
myTolC1=MinTol;
myMaxDerivOrderC2 = 0;
myTolC2=MinTol;
}
//=============================================================================
Extrema_FuncExtCC::Extrema_FuncExtCC (const Curve1& C1,
const Curve2& C2,
const Standard_Real thetol) :
myC1 ((Standard_Address)&C1), myC2 ((Standard_Address)&C2),
myTol (thetol)
{
math_Vector V1(1,2), V2(1,2);
V1(1) = Tool1::FirstParameter(*((Curve1*)myC1));
V2(1) = Tool1::LastParameter(*((Curve1*)myC1));
V1(2) = Tool2::FirstParameter(*((Curve2*)myC2));
V2(2) = Tool2::LastParameter(*((Curve2*)myC2));
SubIntervalInitialize(V1, V2);
switch(Tool1::GetType(*((Curve1*)myC1)))
{
case GeomAbs_BezierCurve:
case GeomAbs_BSplineCurve:
case GeomAbs_OtherCurve:
myMaxDerivOrderC1 = MaxOrder;
myTolC1 = SearchOfTolerance((Standard_Address)&C1);
break;
default:
myMaxDerivOrderC1 = 0;
myTolC1=MinTol;
break;
}
switch(Tool2::GetType(*((Curve2*)myC2)))
{
case GeomAbs_BezierCurve:
case GeomAbs_BSplineCurve:
case GeomAbs_OtherCurve:
myMaxDerivOrderC2 = MaxOrder;
myTolC2 = SearchOfTolerance((Standard_Address)&C2);
break;
default:
myMaxDerivOrderC2 = 0;
myTolC2=MinTol;
break;
}
}
//=============================================================================
void Extrema_FuncExtCC::SetCurve (const Standard_Integer theRank, const Curve1& C)
{
Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_FuncExtCC::SetCurve()")
if (theRank == 1)
{
myC1 = (Standard_Address)&C;
switch(/*Tool1::GetType(*((Curve1*)myC1))*/ C.GetType())
{
case GeomAbs_BezierCurve:
case GeomAbs_BSplineCurve:
case GeomAbs_OtherCurve:
myMaxDerivOrderC1 = MaxOrder;
myTolC1 = SearchOfTolerance((Standard_Address)&C);
break;
default:
myMaxDerivOrderC1 = 0;
myTolC1=MinTol;
break;
}
}
else if (theRank == 2)
{
myC2 = (Standard_Address)&C;
switch(/*Tool2::GetType(*((Curve2*)myC2))*/C.GetType())
{
case GeomAbs_BezierCurve:
case GeomAbs_BSplineCurve:
case GeomAbs_OtherCurve:
myMaxDerivOrderC2 = MaxOrder;
myTolC2 = SearchOfTolerance((Standard_Address)&C);
break;
default:
myMaxDerivOrderC2 = 0;
myTolC2=MinTol;
break;
}
}
}
//=============================================================================
Standard_Boolean Extrema_FuncExtCC::Value (const math_Vector& UV, math_Vector& F)
{
myU = UV(1);
myV = UV(2);
Tool1::D1(*((Curve1*)myC1), myU,myP1,myDu);
Tool2::D1(*((Curve2*)myC2), myV,myP2,myDv);
Vec P1P2 (myP1,myP2);
Standard_Real Ndu = myDu.Magnitude();
if(myMaxDerivOrderC1 != 0)
{
if (Ndu <= myTolC1)
{
//Derivative is approximated by Taylor-series
const Standard_Real DivisionFactor = 1.e-3;
Standard_Real du;
if((myUsupremum >= RealLast()) || (myUinfium <= RealFirst()))
du = 0.0;
else
du = myUsupremum-myUinfium;
const Standard_Real aDelta = Max(du*DivisionFactor,MinStep);
Standard_Integer n = 1; //Derivative order
Vec V;
Standard_Boolean IsDeriveFound;
do
{
V = Tool1::DN(*((Curve1*)myC1),myU,++n);
Ndu = V.Magnitude();
IsDeriveFound = (Ndu > myTolC1);
}
while(!IsDeriveFound && n < myMaxDerivOrderC1);
if(IsDeriveFound)
{
Standard_Real u;
if(myU-myUinfium < aDelta)
u = myU+aDelta;
else
u = myU-aDelta;
Pnt P1, P2;
Tool1::D0(*((Curve1*)myC1),Min(myU, u),P1);
Tool1::D0(*((Curve1*)myC1),Max(myU, u),P2);
Vec V1(P1,P2);
Standard_Real aDirFactor = V.Dot(V1);
if(aDirFactor < 0.0)
myDu = -V;
else
myDu = V;
}//if(IsDeriveFound)
else
{
//Derivative is approximated by three points
Pnt Ptemp; //(0,0,0)-coordinate
Pnt P1, P2, P3;
Standard_Boolean IsParameterGrown;
if(myU-myUinfium < 2*aDelta)
{
Tool1::D0(*((Curve1*)myC1),myU,P1);
Tool1::D0(*((Curve1*)myC1),myU+aDelta,P2);
Tool1::D0(*((Curve1*)myC1),myU+2*aDelta,P3);
IsParameterGrown = Standard_True;
}
else
{
Tool1::D0(*((Curve1*)myC1),myU-2*aDelta,P1);
Tool1::D0(*((Curve1*)myC1),myU-aDelta,P2);
Tool1::D0(*((Curve1*)myC1),myU,P3);
IsParameterGrown = Standard_False;
}
Vec V1(Ptemp,P1), V2(Ptemp,P2), V3(Ptemp,P3);
if(IsParameterGrown)
myDu=-3*V1+4*V2-V3;
else
myDu=V1-4*V2+3*V3;
}//else of if(IsDeriveFound)
Ndu = myDu.Magnitude();
}//if (Ndu <= myTolC1) condition
}//if(myMaxDerivOrder != 0)
if (Ndu <= MinTol)
{
//Warning: 1st derivative of C1 is equal to zero!
return Standard_False;
}
Standard_Real Ndv = myDv.Magnitude();
if(myMaxDerivOrderC2 != 0)
{
if (Ndv <= myTolC2)
{
const Standard_Real DivisionFactor = 1.e-3;
Standard_Real dv;
if((myVsupremum >= RealLast()) || (myVinfium <= RealFirst()))
dv = 0.0;
else
dv = myVsupremum-myVinfium;
const Standard_Real aDelta = Max(dv*DivisionFactor,MinStep);
//Derivative is approximated by Taylor-series
Standard_Integer n = 1; //Derivative order
Vec V;
Standard_Boolean IsDeriveFound;
do
{
V = Tool2::DN(*((Curve2*)myC2),myV,++n);
Ndv = V.Magnitude();
IsDeriveFound = (Ndv > myTolC2);
}
while(!IsDeriveFound && n < myMaxDerivOrderC2);
if(IsDeriveFound)
{
Standard_Real v;
if(myV-myVinfium < aDelta)
v = myV+aDelta;
else
v = myV-aDelta;
Pnt P1, P2;
Tool2::D0(*((Curve2*)myC2),Min(myV, v),P1);
Tool2::D0(*((Curve2*)myC2),Max(myV, v),P2);
Vec V1(P1,P2);
Standard_Real aDirFactor = V.Dot(V1);
if(aDirFactor < 0.0)
myDv = -V;
else
myDv = V;
}//if(IsDeriveFound)
else
{
//Derivative is approximated by three points
Pnt Ptemp; //(0,0,0)-coordinate
Pnt P1, P2, P3;
Standard_Boolean IsParameterGrown;
if(myV-myVinfium < 2*aDelta)
{
Tool2::D0(*((Curve2*)myC2),myV,P1);
Tool2::D0(*((Curve2*)myC2),myV+aDelta,P2);
Tool2::D0(*((Curve2*)myC2),myV+2*aDelta,P3);
IsParameterGrown = Standard_True;
}
else
{
Tool2::D0(*((Curve2*)myC2),myV-2*aDelta,P1);
Tool2::D0(*((Curve2*)myC2),myV-aDelta,P2);
Tool2::D0(*((Curve2*)myC2),myV,P3);
IsParameterGrown = Standard_False;
}
Vec V1(Ptemp,P1), V2(Ptemp,P2), V3(Ptemp,P3);
if(IsParameterGrown)
myDv=-3*V1+4*V2-V3;
else
myDv=V1-4*V2+3*V3;
}//else of if(IsDeriveFound)
Ndv = myDv.Magnitude();
}//if (Ndv <= myTolC2)
}//if(myMaxDerivOrder != 0)
if (Ndv <= MinTol)
{
//1st derivative of C2 is equal to zero!
return Standard_False;
}
F(1) = P1P2.Dot(myDu)/Ndu;
F(2) = P1P2.Dot(myDv)/Ndv;
return Standard_True;
}
//=============================================================================
Standard_Boolean Extrema_FuncExtCC::Derivatives (const math_Vector& UV,
math_Matrix& Df)
{
math_Vector F(1,2);
return Values(UV,F,Df);
}
//=============================================================================
Standard_Boolean Extrema_FuncExtCC::Values (const math_Vector& UV,
math_Vector& F,
math_Matrix& Df)
{
myU = UV(1);
myV = UV(2);
if(Value(UV, F) == Standard_False) //Computes F, myDu, myDv
{
//Warning: No function value found!
return Standard_False;
}//if(Value(UV, F) == Standard_False)
Vec Du, Dv, Duu, Dvv;
Tool1::D2(*((Curve1*)myC1), myU,myP1,Du,Duu);
Tool2::D2(*((Curve2*)myC2), myV,myP2,Dv,Dvv);
//Calling of "Value(...)" function change class member values.
//After running it is necessary to return to previous values.
const Standard_Real myU_old = myU, myV_old = myV;
const Pnt myP1_old = myP1, myP2_old = myP2;
const Vec myDu_old = myDu, myDv_old = myDv;
//Attention: aDelta value must be greater than same value for "Value(...)"
// function to avoid of points' collisions.
const Standard_Real DivisionFactor = 0.01;
Standard_Real du;
if((myUsupremum >= RealLast()) || (myUinfium <= RealFirst()))
du = 0.0;
else
du = myUsupremum-myUinfium;
const Standard_Real aDeltaU = Max(du*DivisionFactor,MinStep);
Standard_Real dv;
if((myVsupremum >= RealLast()) || (myVinfium <= RealFirst()))
dv = 0.0;
else
dv = myVsupremum-myVinfium;
const Standard_Real aDeltaV = Max(dv*DivisionFactor,MinStep);
Vec P1P2 (myP1,myP2);
if((myMaxDerivOrderC1 != 0) && (Du.Magnitude() <= myTolC1))
{
//Derivative is approximated by three points
math_Vector FF1(1,2), FF2(1,2), FF3(1,2);
Standard_Real F1, F2, F3;
/////////////////////////// Search of DF1_u derivative (begin) ///////////////////
if(myU-myUinfium < 2*aDeltaU)
{
F1=F(1);
math_Vector UV2(1,2), UV3(1,2);
UV2(1)=myU+aDeltaU;
UV2(2)=myV;
UV3(1)=myU+2*aDeltaU;
UV3(2)=myV;
if(!((Value(UV2,FF2)) && (Value(UV3,FF3))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F2 = FF2(1);
F3 = FF3(1);
Df(1,1) = (-3*F1+4*F2-F3)/(2.0*aDeltaU);
}//if(myU-myUinfium < 2*aDeltaU)
else
{
F3 = F(1);
math_Vector UV2(1,2), UV1(1,2);
UV2(1)=myU-aDeltaU;
UV2(2)=myV;
UV1(1)=myU-2*aDeltaU;
UV1(2)=myV;
if(!((Value(UV2,FF2)) && (Value(UV1,FF1))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F1 = FF1(1);
F2 = FF2(1);
Df(1,1) = (F1-4*F2+3*F3)/(2.0*aDeltaU);
}//else of if(myU-myUinfium < 2*aDeltaU) condition
/////////////////////////// Search of DF1_u derivative (end) ///////////////////
//Return to previous values
myU = myU_old;
myV = myV_old;
/////////////////////////// Search of DF1_v derivative (begin) ///////////////////
if(myV-myVinfium < 2*aDeltaV)
{
F1=F(1);
math_Vector UV2(1,2), UV3(1,2);
UV2(1)=myU;
UV2(2)=myV+aDeltaV;
UV3(1)=myU;
UV3(2)=myV+2*aDeltaV;
if(!((Value(UV2,FF2)) && (Value(UV3,FF3))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F2 = FF2(1);
F3 = FF3(1);
Df(1,2) = (-3*F1+4*F2-F3)/(2.0*aDeltaV);
}//if(myV-myVinfium < 2*aDeltaV)
else
{
F3 = F(1);
math_Vector UV2(1,2), UV1(1,2);
UV2(1)=myU;
UV2(2)=myV-aDeltaV;
UV1(1)=myU;
UV1(2)=myV-2*aDeltaV;
if(!((Value(UV2,FF2)) && (Value(UV1,FF1))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F1 = FF1(1);
F2 = FF2(1);
Df(1,2) = (F1-4*F2+3*F3)/(2.0*aDeltaV);
}//else of if(myV-myVinfium < 2*aDeltaV)
/////////////////////////// Search of DF1_v derivative (end) ///////////////////
//Return to previous values
myU = myU_old;
myV = myV_old;
myP1 = myP1_old, myP2 = myP2_old;
myDu = myDu_old, myDv = myDv_old;
}//if((myMaxDerivOrderC1 != 0) && (Du.Magnitude() <= myTolC1))
else
{
const Standard_Real Ndu = myDu.Magnitude();
Df(1,1) = - Ndu + (P1P2.Dot(Duu)/Ndu) - F(1)*(myDu.Dot(Duu)/(Ndu*Ndu));
Df(1,2) = myDv.Dot(myDu)/Ndu;
}//else of if((myMaxDerivOrderC1 != 0) && (Du.Magnitude() <= myTolC1))
if((myMaxDerivOrderC2 != 0) && (Dv.Magnitude() <= myTolC2))
{
//Derivative is approximated by three points
math_Vector FF1(1,2), FF2(1,2), FF3(1,2);
Standard_Real F1, F2, F3;
/////////////////////////// Search of DF2_v derivative (begin) ///////////////////
if(myV-myVinfium < 2*aDeltaV)
{
F1=F(2);
math_Vector UV2(1,2), UV3(1,2);
UV2(1)=myU;
UV2(2)=myV+aDeltaV;
UV3(1)=myU;
UV3(2)=myV+2*aDeltaV;
if(!((Value(UV2,FF2)) && (Value(UV3,FF3))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F2 = FF2(2);
F3 = FF3(2);
Df(2,2) = (-3*F1+4*F2-F3)/(2.0*aDeltaV);
}//if(myV-myVinfium < 2*aDeltaV)
else
{
F3 = F(2);
math_Vector UV2(1,2), UV1(1,2);
UV2(1)=myU;
UV2(2)=myV-aDeltaV;
UV1(1)=myU;
UV1(2)=myV-2*aDeltaV;
if(!((Value(UV2,FF2)) && (Value(UV1,FF1))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F1 = FF1(2);
F2 = FF2(2);
Df(2,2) = (F1-4*F2+3*F3)/(2.0*aDeltaV);
}//else of if(myV-myVinfium < 2*aDeltaV)
/////////////////////////// Search of DF2_v derivative (end) ///////////////////
//Return to previous values
myU = myU_old;
myV = myV_old;
/////////////////////////// Search of DF2_u derivative (begin) ///////////////////
if(myU-myUinfium < 2*aDeltaU)
{
F1=F(2);
math_Vector UV2(1,2), UV3(1,2);
UV2(1)=myU+aDeltaU;
UV2(2)=myV;
UV3(1)=myU+2*aDeltaU;
UV3(2)=myV;
if(!((Value(UV2,FF2)) && (Value(UV3,FF3))))
{
//There are many points close to singularity points and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F2 = FF2(2);
F3 = FF3(2);
Df(2,1) = (-3*F1+4*F2-F3)/(2.0*aDeltaU);
}//if(myU-myUinfium < 2*aDelta)
else
{
F3 = F(2);
math_Vector UV2(1,2), UV1(1,2);
UV2(1)=myU-aDeltaU;
UV2(2)=myV;
UV1(1)=myU-2*aDeltaU;
UV1(2)=myV;
if(!((Value(UV2,FF2)) && (Value(UV1,FF1))))
{
//There are many points close to singularity points
//and which have zero-derivative.
//Try to decrease aDelta variable's value.
return Standard_False;
}
F1 = FF1(2);
F2 = FF2(2);
Df(2,1) = (F1-4*F2+3*F3)/(2.0*aDeltaU);
}//else of if(myU-myUinfium < 2*aDeltaU)
/////////////////////////// Search of DF2_u derivative (end) ///////////////////
//Return to previous values
myU = myU_old;
myV = myV_old;
myP1 = myP1_old;
myP2 = myP2_old;
myDu = myDu_old;
myDv = myDv_old;
}//if((myMaxDerivOrderC2 != 0) && (Dv.Magnitude() <= myTolC2))
else
{
Standard_Real Ndv = myDv.Magnitude();
Df(2,2) = Ndv + (P1P2.Dot(Dvv)/Ndv) - F(2)*(myDv.Dot(Dvv)/(Ndv*Ndv));
Df(2,1) = -myDu.Dot(myDv)/Ndv;
}//else of if((myMaxDerivOrderC2 != 0) && (Dv.Magnitude() <= myTolC2))
return Standard_True;
}//end of function
//=============================================================================
Standard_Integer Extrema_FuncExtCC::GetStateNumber ()
{
Vec Du (myDu), Dv (myDv);
Vec P1P2 (myP1, myP2);
Standard_Real mod = Du.Magnitude();
if(mod > myTolC1) {
Du /= mod;
}
mod = Dv.Magnitude();
if(mod > myTolC2) {
Dv /= mod;
}
if (Abs(P1P2.Dot(Du)) <= myTol && Abs(P1P2.Dot(Dv)) <= myTol) {
mySqDist.Append(myP1.SquareDistance(myP2));
myPoints.Append(POnC(myU, myP1));
myPoints.Append(POnC(myV, myP2));
}
return 0;
}
//=============================================================================
void Extrema_FuncExtCC::Points (const Standard_Integer N,
POnC& P1,
POnC& P2) const
{
P1 = myPoints.Value(2*N-1);
P2 = myPoints.Value(2*N);
}
//=============================================================================
void Extrema_FuncExtCC::SubIntervalInitialize(const math_Vector& theInfBound,
const math_Vector& theSupBound)
{
myUinfium = theInfBound(1);
myUsupremum = theSupBound(1);
myVinfium = theInfBound(2);
myVsupremum = theSupBound(2);
}
//=============================================================================