mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-10 18:51:21 +03:00
0024303: Precision degradation for Geom2dGcc_Circ2d2TanRad in OCCT6.6.0.
1. DRAW-command. 2. Initial point (the center of found circle), which is found by standard algorithm, is precised in function PrecRoot(...). Correction is called, if and only if initial point is in tangent zone. 3. Handling of possible divergences and of possible exceptions in PrecRoot() function is added. Test cases for issue CR24303
This commit is contained in:
parent
c24d401753
commit
74f5f8df5d
@ -525,6 +525,198 @@ GccGeo_Circ2d2TanRad::
|
||||
}
|
||||
}
|
||||
|
||||
static void PrecRoot(const TheParGenCurve& theC1,
|
||||
const TheParGenCurve& theC2,
|
||||
const Standard_Real theU0,
|
||||
const Standard_Real theV0,
|
||||
const Standard_Real theUmin,
|
||||
const Standard_Real theUmax,
|
||||
const Standard_Real theVmin,
|
||||
const Standard_Real theVmax,
|
||||
Standard_Real& theUfinal,
|
||||
Standard_Real& theVfinal)
|
||||
{
|
||||
const Standard_Real aInitStepU = (theUmax - theUmin)/2.0,
|
||||
aInitStepV = (theVmax - theVmin)/2.0;
|
||||
|
||||
Standard_Real aStepU = aInitStepU, aStepV = aInitStepV;
|
||||
|
||||
const Standard_Real aTol = Precision::PConfusion() * Precision::PConfusion();
|
||||
const Standard_Integer aNbIterMax = 100;
|
||||
|
||||
gp_Pnt2d aP1, aP2;
|
||||
gp_Vec2d aD1, aD2;
|
||||
|
||||
TheCurvePGTool::D1(theC1, theU0, aP1, aD1);
|
||||
TheCurvePGTool::D1(theC2, theV0, aP2, aD2);
|
||||
|
||||
gp_Vec2d vP12(aP1.XY() - aP2.XY());
|
||||
|
||||
Standard_Real aU = theU0, aV = theV0;
|
||||
theUfinal = theU0;
|
||||
theVfinal = theV0;
|
||||
|
||||
Standard_Real aSQDistPrev = aP1.SquareDistance(aP2);
|
||||
|
||||
Standard_Integer aNbIter = 1;
|
||||
|
||||
do
|
||||
{
|
||||
Standard_Real aDetH = aD1.Y()*aD2.X() - aD1.X()*aD2.Y();
|
||||
if(aDetH == 0.0)
|
||||
break;
|
||||
|
||||
aU += aStepU*(aD2.Y() * vP12.X() - aD2.X()*vP12.Y())/aDetH;
|
||||
aV += aStepV*(aD1.Y() * vP12.X() - aD1.X()*vP12.Y())/aDetH;
|
||||
|
||||
if(Abs(aU - theUmin) > 1000.0)
|
||||
//method diverges
|
||||
return;
|
||||
|
||||
if(Abs(aU - theUmax) > 1000.0)
|
||||
//method diverges
|
||||
return;
|
||||
|
||||
if(Abs(aV - theVmin) > 1000.0)
|
||||
//method diverges
|
||||
return;
|
||||
|
||||
if(Abs(aV - theVmax) > 1000.0)
|
||||
//method diverges
|
||||
return;
|
||||
|
||||
TheCurvePGTool::D1(theC1, aU, aP1, aD1);
|
||||
TheCurvePGTool::D1(theC2, aV, aP2, aD2);
|
||||
const Standard_Real aSQDist = aP1.SquareDistance(aP2);
|
||||
|
||||
if(Precision::IsInfinite(aSQDist))
|
||||
//method diverges
|
||||
return;
|
||||
|
||||
vP12.SetXY(aP1.XY() - aP2.XY());
|
||||
|
||||
if(aSQDist < aSQDistPrev)
|
||||
{
|
||||
aSQDistPrev = aSQDist;
|
||||
aStepU = aInitStepU;
|
||||
aStepV = aInitStepV;
|
||||
theUfinal = aU;
|
||||
theVfinal = aV;
|
||||
}
|
||||
else
|
||||
{
|
||||
aStepU /= 2.0;
|
||||
aStepV /= 2.0;
|
||||
}
|
||||
}
|
||||
while((aNbIter++ < aNbIterMax) && ((aStepU > aTol) || (aStepV > aTol)));
|
||||
|
||||
Standard_Boolean isInBound = Standard_True;
|
||||
if(theUfinal < theUmin)
|
||||
{
|
||||
aU = theUfinal;
|
||||
aV = theVfinal;
|
||||
|
||||
theUfinal = theUmin;
|
||||
isInBound = Standard_False;
|
||||
}
|
||||
|
||||
if(theUfinal > theUmax)
|
||||
{
|
||||
aU = theUfinal;
|
||||
aV = theVfinal;
|
||||
|
||||
theUfinal = theUmax;
|
||||
isInBound = Standard_False;
|
||||
}
|
||||
|
||||
if(!isInBound)
|
||||
{
|
||||
TheCurvePGTool::D1(theC1, aU, aP1, aD1);
|
||||
TheCurvePGTool::D1(theC2, aV, aP2, aD2);
|
||||
Standard_Real aV1 = (aD2.X() == 0.0) ? aV :((theUfinal - aU)*aD1.X() + aV*aD2.X() + (aP1.X() - aP2.X()))/aD2.X();
|
||||
Standard_Real aV2 = (aD2.Y() == 0.0) ? aV :((theUfinal - aU)*aD1.Y() + aV*aD2.Y() + (aP1.Y() - aP2.Y()))/aD2.Y();
|
||||
|
||||
if(aV1 < theVmin)
|
||||
aV1 = theVmin;
|
||||
|
||||
if(aV1 > theVmax)
|
||||
aV1 = theVmax;
|
||||
|
||||
if(aV2 < theVmin)
|
||||
aV2 = theVmin;
|
||||
|
||||
if(aV2 > theVmax)
|
||||
aV2 = theVmax;
|
||||
|
||||
aP1 = TheCurvePGTool::Value(theC1,theUfinal);
|
||||
aP2 = TheCurvePGTool::Value(theC2,aV1);
|
||||
|
||||
Standard_Real aSQ1 = aP1.SquareDistance(aP2);
|
||||
|
||||
aP2 = TheCurvePGTool::Value(theC2,aV2);
|
||||
Standard_Real aSQ2 = aP1.SquareDistance(aP2);
|
||||
|
||||
if(aSQ1 < aSQ2)
|
||||
theVfinal = aV1;
|
||||
else
|
||||
theVfinal = aV2;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(theVfinal < theVmin)
|
||||
{
|
||||
aU = theUfinal;
|
||||
aV = theVfinal;
|
||||
|
||||
theVfinal = theVmin;
|
||||
isInBound = Standard_False;
|
||||
}
|
||||
|
||||
if(theVfinal > theVmax)
|
||||
{
|
||||
aU = theUfinal;
|
||||
aV = theVfinal;
|
||||
|
||||
theVfinal = theVmax;
|
||||
isInBound = Standard_False;
|
||||
}
|
||||
|
||||
if(isInBound)
|
||||
return;
|
||||
|
||||
TheCurvePGTool::D1(theC1, aU, aP1, aD1);
|
||||
TheCurvePGTool::D1(theC2, aV, aP2, aD2);
|
||||
Standard_Real aU1 = (aD1.X() == 0.0) ? aU :((theVfinal - aV)*aD2.X() + aU*aD1.X() + (aP2.X() - aP1.X()))/aD1.X();
|
||||
Standard_Real aU2 = (aD1.Y() == 0.0) ? aU :((theVfinal - aV)*aD2.Y() + aU*aD1.Y() + (aP2.Y() - aP1.Y()))/aD1.Y();
|
||||
|
||||
if(aU1 < theUmin)
|
||||
aU1 = theUmin;
|
||||
|
||||
if(aU1 > theUmax)
|
||||
aU1 = theUmax;
|
||||
|
||||
if(aU2 < theUmin)
|
||||
aU2 = theUmin;
|
||||
|
||||
if(aU2 > theUmax)
|
||||
aU2 = theUmax;
|
||||
|
||||
aP2 = TheCurvePGTool::Value(theC2,theVfinal);
|
||||
aP1 = TheCurvePGTool::Value(theC1,aU1);
|
||||
|
||||
Standard_Real aSQ1 = aP1.SquareDistance(aP2);
|
||||
|
||||
aP1 = TheCurvePGTool::Value(theC1,aU2);
|
||||
Standard_Real aSQ2 = aP1.SquareDistance(aP2);
|
||||
|
||||
if(aSQ1 < aSQ2)
|
||||
theUfinal = aU1;
|
||||
else
|
||||
theUfinal = aU2;
|
||||
}
|
||||
|
||||
// circulaire tant a deux courbes ,de rayon donne
|
||||
//==================================================
|
||||
|
||||
@ -686,9 +878,41 @@ GccGeo_Circ2d2TanRad::
|
||||
Intp.Perform(C1,C2,Tol,Tol);
|
||||
if (Intp.IsDone()) {
|
||||
if (!Intp.IsEmpty()) {
|
||||
for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++) {
|
||||
for (Standard_Integer i = 1 ; i <= Intp.NbPoints() ; i++)
|
||||
{
|
||||
Standard_Real aU0 = Intp.Point(i).ParamOnFirst();
|
||||
Standard_Real aV0 = Intp.Point(i).ParamOnSecond();
|
||||
|
||||
Standard_Real aU1 = aU0-Precision::PApproximation();
|
||||
Standard_Real aV1 = aV0-Precision::PApproximation();
|
||||
|
||||
Standard_Real aU2 = aU0+Precision::PApproximation();
|
||||
Standard_Real aV2 = aV0+Precision::PApproximation();
|
||||
|
||||
gp_Pnt2d P11 = TheCurvePGTool::Value(C1,aU1);
|
||||
gp_Pnt2d P12 = TheCurvePGTool::Value(C2,aV1);
|
||||
gp_Pnt2d P21 = TheCurvePGTool::Value(C1,aU2);
|
||||
gp_Pnt2d P22 = TheCurvePGTool::Value(C2,aV2);
|
||||
|
||||
Standard_Real aDist1112 = P11.Distance(P12);
|
||||
Standard_Real aDist1122 = P11.Distance(P22);
|
||||
|
||||
Standard_Real aDist1221 = P12.Distance(P21);
|
||||
Standard_Real aDist2122 = P21.Distance(P22);
|
||||
|
||||
if( Min(aDist1112, aDist1122) <= Precision::Approximation() &&
|
||||
Min(aDist1221, aDist2122) <= Precision::Approximation())
|
||||
{
|
||||
PrecRoot(C1, C2, aU0, aV0,
|
||||
Max(TheCurvePGTool::FirstParameter(C1), aU0 - 10.0),
|
||||
Min(TheCurvePGTool::LastParameter(C1), aU0 + 10.0),
|
||||
Max(TheCurvePGTool::FirstParameter(C2), aV0 - 10.0),
|
||||
Min(TheCurvePGTool::LastParameter(C2), aV0 + 10.0),
|
||||
aU0, aV0);
|
||||
}
|
||||
|
||||
NbrSol++;
|
||||
gp_Pnt2d Center(Intp.Point(i).Value());
|
||||
gp_Pnt2d Center(TheCurvePGTool::Value(C1, aU0));
|
||||
cirsol(NbrSol) = gp_Circ2d(gp_Ax2d(Center,dirx),Radius);
|
||||
// =======================================================
|
||||
qualifier1(NbrSol) = Qualified1.Qualifier();
|
||||
@ -705,6 +929,7 @@ GccGeo_Circ2d2TanRad::
|
||||
pnttg2sol(NbrSol));
|
||||
}
|
||||
}
|
||||
|
||||
WellDone = Standard_True;
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +148,85 @@ static Standard_Integer OCC137_z (Draw_Interpretor& di, Standard_Integer argc, c
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <GccEnt_Position.hxx>
|
||||
#include <Geom2dGcc_QualifiedCurve.hxx>
|
||||
#include <Geom2dGcc_Circ2d2TanRad.hxx>
|
||||
#include <gp_Elips2d.hxx>
|
||||
#include <Geom2d_Ellipse.hxx>
|
||||
#include <Geom2d_Circle.hxx>
|
||||
|
||||
static Standard_Integer OCC24303(Draw_Interpretor& di, Standard_Integer n, const char** a)
|
||||
{
|
||||
if(n < 2)
|
||||
return 1;
|
||||
|
||||
const Standard_Integer SolID = Draw::Atoi(a[1]);
|
||||
|
||||
//Ellipses
|
||||
Standard_Real majorRadius = 2.0;
|
||||
Standard_Real minorRadius = 1.0;
|
||||
gp_Pnt2d p0(gp::Origin2d());
|
||||
gp_Pnt2d p1(4.0,0.0);
|
||||
|
||||
gp_Elips2d ellipse1 = gp_Elips2d( gp_Ax2d(p0,gp::DX2d()),majorRadius, minorRadius,true);
|
||||
gp_Elips2d ellipse2 = gp_Elips2d( gp_Ax2d(p1,gp::DX2d()),majorRadius, minorRadius,true);
|
||||
|
||||
Handle_Geom2d_Curve curve1 = new Geom2d_Ellipse(ellipse1);
|
||||
Handle_Geom2d_Curve curve2 = new Geom2d_Ellipse(ellipse2);
|
||||
DrawTrSurf::Set("c1", curve1);
|
||||
DrawTrSurf::Set("c2", curve2);
|
||||
//Expected tangent
|
||||
gp_Pnt2d centre(5.0,0.0);
|
||||
Standard_Real radius = 3.0;
|
||||
gp_Circ2d theorical_tangent = gp_Circ2d(gp_Ax2d(centre,gp::DX2d()),radius);
|
||||
|
||||
//Calculate the tangent with Geom2dGcc_Circ2dTanRan
|
||||
|
||||
const Geom2dAdaptor_Curve AdaptedCurve1 ( curve1 );
|
||||
const Geom2dAdaptor_Curve AdaptedCurve2 ( curve2 );
|
||||
|
||||
GccEnt_Position curveQualif1 = GccEnt_unqualified;
|
||||
GccEnt_Position curveQualif2 = GccEnt_unqualified;
|
||||
|
||||
const Geom2dGcc_QualifiedCurve qualifiedCurve1 ( AdaptedCurve1, curveQualif1 );
|
||||
const Geom2dGcc_QualifiedCurve qualifiedCurve2 ( AdaptedCurve2, curveQualif2 );
|
||||
|
||||
const Geom2dGcc_Circ2d2TanRad circCalc(qualifiedCurve1,qualifiedCurve2,radius,/*Precision::Approximation()*/ 1.0e-9);
|
||||
|
||||
const Standard_Integer aNbSol = circCalc.NbSolutions();
|
||||
di << "Solutions " << aNbSol << "\n";
|
||||
|
||||
if((SolID < 1) || (SolID > aNbSol))
|
||||
{
|
||||
di << "Wrong SolID value\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
gp_Circ2d calculated_tangent = circCalc.ThisSolution(SolID);
|
||||
|
||||
char Buf[10];
|
||||
for (Standard_Integer i = 1; i <= aNbSol; i++)
|
||||
{
|
||||
gp_Circ2d ct = circCalc.ThisSolution(i);
|
||||
Handle (Geom2d_Circle) GSol = new Geom2d_Circle(ct);
|
||||
Sprintf(Buf, "Sol%d",i);
|
||||
DrawTrSurf::Set(Buf, GSol);
|
||||
}
|
||||
|
||||
//This distance is different in OC 6.5.4 and OC 6.6.0
|
||||
Standard_Real dist = theorical_tangent.Location().Distance(calculated_tangent.Location());
|
||||
di << "Distance = " << dist << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QABugs::Commands_9(Draw_Interpretor& theCommands) {
|
||||
const char *group = "QABugs";
|
||||
|
||||
theCommands.Add ("BUC60857", "BUC60857", __FILE__, BUC60857, group);
|
||||
theCommands.Add("OCC137","OCC137 mode [shape]",__FILE__,OCC137,group);
|
||||
theCommands.Add("OCC137_z","OCC137_z [ZDetection_mode]",__FILE__,OCC137_z,group);
|
||||
theCommands.Add("OCC24303", "OCC24303 SolID ", __FILE__, OCC24303,group);
|
||||
|
||||
return;
|
||||
}
|
||||
|
67
tests/bugs/modalg_5/bug24303
Executable file
67
tests/bugs/modalg_5/bug24303
Executable file
@ -0,0 +1,67 @@
|
||||
puts "============"
|
||||
puts "OCC24303"
|
||||
puts "============"
|
||||
puts ""
|
||||
###############################
|
||||
## Precision degradation for Geom2dGcc_Circ2d2TanRad in OCCT6.6.0.
|
||||
###############################
|
||||
|
||||
pload QAcommands
|
||||
|
||||
set status 0
|
||||
|
||||
set info1 [OCC24303 4]
|
||||
regexp {Solutions +([-0-9.+eE]+)} ${info1} full Solution
|
||||
regexp {Distance += +([-0-9.+eE]+)} ${info1} full Distance
|
||||
|
||||
if { [info exists Sol4] } {
|
||||
set info2 [dump Sol4]
|
||||
regexp {Center +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full CenterX CenterY
|
||||
regexp {XAxis +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full XAxisX XAxisY
|
||||
regexp {YAxis +:([-0-9.+eE]+), +([-0-9.+eE]+)} ${info2} full YAxisX YAxisY
|
||||
regexp {Radius +:([-0-9.+eE]+)} ${info2} full Radius
|
||||
set good_CenterX 5
|
||||
set good_CenterY 0
|
||||
set good_XAxisX 1
|
||||
set good_XAxisY 0
|
||||
set good_YAxisX 0
|
||||
set good_YAxisY 1
|
||||
set good_Radius 3
|
||||
if { ${CenterX} != ${good_CenterX} } {
|
||||
puts "Faulty : Bad CenterX"
|
||||
set status 1
|
||||
}
|
||||
if { ${CenterY} != ${good_CenterY} } {
|
||||
puts "Faulty : Bad CenterY"
|
||||
set status 1
|
||||
}
|
||||
if { ${XAxisX} != ${good_XAxisX} } {
|
||||
puts "Faulty : Bad XAxisX"
|
||||
set status 1
|
||||
}
|
||||
if { ${XAxisY} != ${good_XAxisY} } {
|
||||
puts "Faulty : Bad XAxisY"
|
||||
set status 1
|
||||
}
|
||||
if { ${YAxisX} != ${good_YAxisX} } {
|
||||
puts "Faulty : Bad YAxisX"
|
||||
set status 1
|
||||
}
|
||||
if { ${YAxisY} != ${good_YAxisY} } {
|
||||
puts "Faulty : Bad YAxisY"
|
||||
set status 1
|
||||
}
|
||||
if { ${Radius} != ${good_Radius} } {
|
||||
puts "Faulty : Bad Radius"
|
||||
set status 1
|
||||
}
|
||||
} else {
|
||||
puts "Faulty : Bad solution"
|
||||
set status 1
|
||||
}
|
||||
|
||||
if { ${status} != 0 } {
|
||||
puts "Faulty : solution is wrong"
|
||||
} else {
|
||||
puts "OK : solution is correct"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user