1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-03 14:10:33 +03:00

0026351: Wrong result found by the projection algorithm

C2 continuity intervals changed to Knots intervals in case of Bspline curve.
Fixed incorrect extremaPC usage.

Test case for issue CR26351
Update of test-cases according to the new behavior
This commit is contained in:
aml
2015-06-24 15:44:28 +03:00
committed by bugmaster
parent e03bdee2e1
commit c8bf1eb747
43 changed files with 405 additions and 203 deletions

View File

@@ -1204,14 +1204,16 @@ void Draft_Modification::Perform ()
Dist2Min = RealLast();
for (i = 1; i <= myExtPC.NbExt(); i++)
{
Dist2 = myExtPC.SquareDistance(i);
if (Dist2 < Dist2Min)
{
Dist2Min = Dist2;
pmin = myExtPC.Point(i).Parameter();
}
if (myExtPC.IsMin(i))
{
Dist2 = myExtPC.SquareDistance(i);
if (Dist2 < Dist2Min)
{
Dist2Min = Dist2;
pmin = myExtPC.Point(i).Parameter();
}
}
}
newC->D1(pmin,pfv,newd1);
Standard_Boolean YaRev = d1fv.Dot(newd1) < 0.;
@@ -1978,7 +1980,7 @@ static Standard_Real Parameter(const Handle(Geom_Curve)& C,
GeomAdaptor_Curve TheCurve(C);
Extrema_ExtPC myExtPC(P,TheCurve);
if (!myExtPC.IsDone()) {
Standard_Failure::Raise();
Standard_Failure::Raise("Draft_Modification_1::Parameter: ExtremaPC not done.");
}
if (myExtPC.NbExt() >= 1) {
Standard_Real Dist2, Dist2Min = myExtPC.SquareDistance(1);

View File

@@ -364,17 +364,18 @@ Standard_Integer Extrema_FuncExtPC::GetStateNumber ()
{
if (!myPinit || !myCinit) Standard_TypeMismatch::Raise();
mySqDist.Append(myPc.SquareDistance(myP));
Standard_Integer IntVal;
if (!myD1Init) {
myD1Init = Standard_True;
Standard_Real FF, DD;
Values(myU, FF, DD);
}
if (!myD1Init) IntVal = 0;
else {
if (myD1f > 0.) { IntVal = 1; }
else { IntVal = 0; }
// It is necessary to always compute myD1f.
myD1Init = Standard_True;
Standard_Real FF, DD;
Values(myU, FF, DD);
Standard_Integer IntVal = 0;
if (myD1f > 0.0)
{
IntVal = 1;
}
myIsMin.Append(IntVal);
myPoint.Append(POnC(myU,myPc));
return 0;

View File

@@ -28,13 +28,13 @@
#include <Precision.hxx>
#include <ElCLib.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <NCollection_Array1.hxx>
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void Extrema_GExtPC::Perform(const ThePoint& P)
{
mySqDist.Clear();
@@ -56,58 +56,203 @@ void Extrema_GExtPC::Perform(const ThePoint& P)
mydist2 = P.SquareDistance(Pl);
}
TheCurve & aCurve = *((TheCurve*)myC);
switch(type) {
case GeomAbs_Circle:
{
myExtPElC.Perform(P, TheCurveTool::Circle(*((TheCurve*)myC)), t3d, myuinf, myusup);
myExtPElC.Perform(P, TheCurveTool::Circle(aCurve), t3d, myuinf, myusup);
}
break;
case GeomAbs_Ellipse:
{
myExtPElC.Perform(P, TheCurveTool::Ellipse(*((TheCurve*)myC)), t3d, myuinf, myusup);
myExtPElC.Perform(P, TheCurveTool::Ellipse(aCurve), t3d, myuinf, myusup);
}
break;
case GeomAbs_Parabola:
{
myExtPElC.Perform(P, TheCurveTool::Parabola(*((TheCurve*)myC)), t3d,myuinf,myusup);
myExtPElC.Perform(P, TheCurveTool::Parabola(aCurve), t3d,myuinf,myusup);
}
break;
case GeomAbs_Hyperbola:
{
myExtPElC.Perform(P,TheCurveTool::Hyperbola(*((TheCurve*)myC)),t3d, myuinf, myusup);
myExtPElC.Perform(P,TheCurveTool::Hyperbola(aCurve),t3d, myuinf, myusup);
}
break;
case GeomAbs_Line:
{
myExtPElC.Perform(P, TheCurveTool::Line(*((TheCurve*)myC)), t3d, myuinf, myusup);
myExtPElC.Perform(P, TheCurveTool::Line(aCurve), t3d, myuinf, myusup);
}
break;
case GeomAbs_BezierCurve:
{
myintuinf = myuinf;
myintusup = myusup;
mysample = (TheCurveTool::Bezier(*((TheCurve*)myC)))->NbPoles()*2;
mysample = (TheCurveTool::Bezier(aCurve))->NbPoles() * 2;
myExtPC.Initialize(aCurve);
IntervalPerform(P);
return;
}
case GeomAbs_BSplineCurve:
{
mysample = (TheCurveTool::BSpline(*((TheCurve*)myC)))->NbPoles()*2;
const Standard_Integer
aFirstIdx = TheCurveTool::BSpline(aCurve)->FirstUKnotIndex(),
aLastIdx = TheCurveTool::BSpline(aCurve)->LastUKnotIndex();
// const reference can not be used due to implementation of BRep_Adaptor.
TColStd_Array1OfReal aKnots(aFirstIdx, aLastIdx);
TheCurveTool::BSpline(aCurve)->Knots(aKnots);
// Workaround to work with:
// blend, where knots may be moved from param space.
Standard_Real aPeriodJump = 0.0;
if (TheCurveTool::IsPeriodic(aCurve))
{
Standard_Integer aPeriodShift =
Standard_Integer ((myuinf - aKnots(aFirstIdx)) / TheCurveTool::Period(aCurve));
if (myuinf < aKnots(aFirstIdx))
aPeriodShift--;
aPeriodJump = TheCurveTool::Period(aCurve) * aPeriodShift;
}
Standard_Integer anIdx;
// Find first and last used knot
Standard_Integer aFirstUsedKnot = aFirstIdx,
aLastUsedKnot = aLastIdx;
for(anIdx = aFirstIdx; anIdx <= aLastIdx; anIdx++)
{
Standard_Real aKnot = aKnots(anIdx) + aPeriodJump;
if (myuinf >= aKnot)
aFirstUsedKnot = anIdx;
else
break;
}
for(anIdx = aLastIdx; anIdx >= aFirstIdx; anIdx--)
{
Standard_Real aKnot = aKnots(anIdx) + aPeriodJump;
if (myusup <= aKnot)
aLastUsedKnot = anIdx;
else
break;
}
mysample = (TheCurveTool::BSpline(aCurve))->Degree() + 1;
// Fill sample points.
Standard_Integer aValIdx = 1;
NCollection_Array1<Standard_Real> aVal(1, (mysample) * (aLastUsedKnot - aFirstUsedKnot) + 1);
NCollection_Array1<Standard_Real> aParam(1, (mysample) * (aLastUsedKnot - aFirstUsedKnot) + 1);
for(anIdx = aFirstUsedKnot; anIdx < aLastUsedKnot; anIdx++)
{
Standard_Real aF = aKnots(anIdx) + aPeriodJump,
aL = aKnots(anIdx + 1) + aPeriodJump;
if (anIdx == aFirstUsedKnot)
aF = myuinf;
if (anIdx == aLastUsedKnot - 1)
aL = myusup;
Standard_Real aStep = (aL - aF) / mysample;
for(Standard_Integer aPntIdx = 0; aPntIdx < mysample; aPntIdx++)
{
Standard_Real aCurrentParam = aF + aStep * aPntIdx;
aVal(aValIdx) = TheCurveTool::Value(aCurve, aCurrentParam).SquareDistance(P);
aParam(aValIdx) = aCurrentParam;
aValIdx++;
}
}
// Fill last point.
aVal(aValIdx) = TheCurveTool::Value(aCurve, myusup).SquareDistance(P);
aParam(aValIdx) = myusup;
myExtPC.Initialize(aCurve);
// Find extremas.
for(anIdx = aVal.Lower() + 1; anIdx < aVal.Upper(); anIdx++)
{
if (aVal(anIdx) <= Precision::SquareConfusion())
{
mySqDist.Append(aVal(anIdx));
myismin.Append(Standard_True);
mypoint.Append(ThePOnC(aParam(anIdx), TheCurveTool::Value(aCurve, aParam(anIdx))));
}
if ((aVal(anIdx) >= aVal(anIdx + 1) &&
aVal(anIdx) >= aVal(anIdx - 1)) ||
(aVal(anIdx) <= aVal(anIdx + 1) &&
aVal(anIdx) <= aVal(anIdx - 1)) )
{
myintuinf = aParam(anIdx - 1);
myintusup = aParam(anIdx + 1);
IntervalPerform(P);
}
}
// Solve on first and last interval.
if (mydist1 > Precision::SquareConfusion())
{
ThePoint aP1, aP2;
TheVector aV1, aV2;
TheCurveTool::D1(aCurve, aParam.Value(aParam.Lower()), aP1, aV1);
TheCurveTool::D1(aCurve, aParam.Value(aParam.Lower() + 1), aP2, aV2);
TheVector aBase1(P, aP1), aBase2(P, aP2);
Standard_Real aVal1 = aV1.Dot(aBase1); // Derivative of (C(u) - P)^2
Standard_Real aVal2 = aV2.Dot(aBase2); // Derivative of (C(u) - P)^2
// Derivatives have opposite signs - min or max inside of interval (sufficient condition).
// Necessary condition - when point lies on curve.
if(aVal1 * aVal2 <= 0.0 ||
aBase1.Dot(aBase2) <= 0.0)
{
myintuinf = aParam(aVal.Lower());
myintusup = aParam(aVal.Lower() + 1);
IntervalPerform(P);
}
}
if (mydist2 > Precision::SquareConfusion())
{
ThePoint aP1, aP2;
TheVector aV1, aV2;
TheCurveTool::D1(aCurve, aParam.Value(aParam.Upper() - 1), aP1, aV1);
TheCurveTool::D1(aCurve, aParam.Value(aParam.Upper()), aP2, aV2);
TheVector aBase1(P, aP1), aBase2(P, aP2);
Standard_Real aVal1 = aV1.Dot(aBase1); // Derivative of (C(u) - P)^2
Standard_Real aVal2 = aV2.Dot(aBase2); // Derivative of (C(u) - P)^2
// Derivatives have opposite signs - min or max inside of interval (sufficient condition).
// Necessary condition - when point lies on curve.
if(aVal1 * aVal2 <= 0.0 ||
aBase1.Dot(aBase2) <= 0.0)
{
myintuinf = aParam(aVal.Upper() - 1);
myintusup = aParam(aVal.Upper());
IntervalPerform(P);
}
}
mydone = Standard_True;
break;
}
case GeomAbs_OtherCurve:
case GeomAbs_OtherCurve:
{
Standard_Boolean IntExtIsDone = Standard_False;
Standard_Boolean IntIsNotValid;
n = TheCurveTool::NbIntervals(*((TheCurve*)myC), GeomAbs_C2);
n = TheCurveTool::NbIntervals(aCurve, GeomAbs_C2);
TColStd_Array1OfReal theInter(1, n+1);
Standard_Boolean isPeriodic = TheCurveTool::IsPeriodic(*((TheCurve*)myC));
TheCurveTool::Intervals(*((TheCurve*)myC), theInter, GeomAbs_C2);
Standard_Boolean isPeriodic = TheCurveTool::IsPeriodic(aCurve);
TheCurveTool::Intervals(aCurve, theInter, GeomAbs_C2);
mysample = Max(mysample/n, 17);
TheVector V1;
ThePoint PP;
Standard_Real s1 = 0.0 ;
Standard_Real s2 = 0.0;
for (i = 1; i <= n; i++) {
Standard_Real s2 = 0.0;
myExtPC.Initialize(aCurve);
for (i = 1; i <= n; i++)
{
myintuinf = theInter(i);
myintusup = theInter(i+1);
@@ -115,7 +260,7 @@ void Extrema_GExtPC::Perform(const ThePoint& P)
Standard_Real aSupToCheck = myintusup;
if (isPeriodic) {
Standard_Real aPeriod = TheCurveTool::Period(*((TheCurve*)myC));
Standard_Real aPeriod = TheCurveTool::Period(aCurve);
anInfToCheck = ElCLib::InPeriod(myintuinf, myuinf, myuinf+aPeriod);
aSupToCheck = myintusup+(anInfToCheck-myintuinf);
}
@@ -129,7 +274,7 @@ void Extrema_GExtPC::Perform(const ThePoint& P)
if (i != 1)
{
TheCurveTool::D1(*((TheCurve*)myC), myintuinf, PP, V1);
TheCurveTool::D1(aCurve, myintuinf, PP, V1);
s1 = (TheVector(P, PP))*V1;
if (s1*s2 < 0.0) {
mySqDist.Append(PP.SquareDistance(P));
@@ -138,65 +283,80 @@ void Extrema_GExtPC::Perform(const ThePoint& P)
}
}
if (i != n) {
TheCurveTool::D1(*((TheCurve*)myC), myintusup, PP, V1);
TheCurveTool::D1(aCurve, myintusup, PP, V1);
s2 = (TheVector(P, PP))*V1;
}
IntervalPerform(P);
IntExtIsDone = IntExtIsDone || mydone;
}
mydone = IntExtIsDone;
// Additional checking if the point is on the first or last point of the curve and does not added yet
if (mydist1 < Precision::SquareConfusion() || mydist2 < Precision::SquareConfusion())
{
Standard_Boolean isFirstAdded = Standard_False;
Standard_Boolean isLastAdded = Standard_False;
Standard_Integer aNbPoints = mypoint.Length();
for (i = 1; i <= aNbPoints; i++)
{
U = mypoint.Value(i).Parameter();
if (Abs(U - myuinf) < mytolu)
isFirstAdded = Standard_True;
else if (Abs(myusup - U) < mytolu)
isLastAdded = Standard_True;
}
if (!isFirstAdded && mydist1 < Precision::SquareConfusion())
{
mySqDist.Prepend(mydist1);
myismin.Prepend(Standard_True);
mypoint.Prepend(ThePOnC(myuinf, Pf));
}
if (!isLastAdded && mydist2 < Precision::SquareConfusion())
{
mySqDist.Append(mydist2);
myismin.Append(Standard_True);
mypoint.Append(ThePOnC(myusup, Pl));
}
}
return;
mydone = IntExtIsDone;
break;
}
}
mydone = myExtPElC.IsDone();
if (mydone) {
NbExt = myExtPElC.NbExt();
for (i = 1; i <= NbExt; i++) {
// Verification de la validite des parametres:
ThePOnC PC = myExtPElC.Point(i);
U = PC.Parameter();
if (TheCurveTool::IsPeriodic(*((TheCurve*)myC))) {
U = ElCLib::InPeriod(U, myuinf, myuinf+TheCurveTool::Period(*((TheCurve*)myC)));
// Postprocessing.
if (type == GeomAbs_BSplineCurve ||
type == GeomAbs_OtherCurve)
{
// Additional checking if the point is on the first or last point of the curve
// and does not added yet.
if (mydist1 < Precision::SquareConfusion() ||
mydist2 < Precision::SquareConfusion())
{
Standard_Boolean isFirstAdded = Standard_False;
Standard_Boolean isLastAdded = Standard_False;
Standard_Integer aNbPoints = mypoint.Length();
for (i = 1; i <= aNbPoints; i++)
{
U = mypoint.Value(i).Parameter();
if (Abs(U - myuinf) < mytolu)
isFirstAdded = Standard_True;
else if (Abs(myusup - U) < mytolu)
isLastAdded = Standard_True;
}
if ((U >= myuinf-mytolu) && (U <= myusup+mytolu)){
PC.SetValues(U, myExtPElC.Point(i).Value());
mySqDist.Append(myExtPElC.SquareDistance(i));
myismin.Append(myExtPElC.IsMin(i));
mypoint.Append(PC);
if (!isFirstAdded && mydist1 < Precision::SquareConfusion())
{
mySqDist.Prepend(mydist1);
myismin.Prepend(Standard_True);
mypoint.Prepend(ThePOnC(myuinf, Pf));
}
if (!isLastAdded && mydist2 < Precision::SquareConfusion())
{
mySqDist.Append(mydist2);
myismin.Append(Standard_True);
mypoint.Append(ThePOnC(myusup, Pl));
}
mydone = Standard_True;
}
}
else
{
// In analytical case
mydone = myExtPElC.IsDone();
if (mydone)
{
NbExt = myExtPElC.NbExt();
for (i = 1; i <= NbExt; i++)
{
// Verification de la validite des parametres:
ThePOnC PC = myExtPElC.Point(i);
U = PC.Parameter();
if (TheCurveTool::IsPeriodic(aCurve))
{
U = ElCLib::InPeriod(U, myuinf, myuinf+TheCurveTool::Period(aCurve));
}
if ((U >= myuinf-mytolu) && (U <= myusup+mytolu))
{
PC.SetValues(U, myExtPElC.Point(i).Value());
mySqDist.Append(myExtPElC.SquareDistance(i));
myismin.Append(myExtPElC.IsMin(i));
mypoint.Append(PC);
}
}
}
}
}
}
@@ -232,20 +392,23 @@ void Extrema_GExtPC::IntervalPerform(const ThePoint& P)
{
Standard_Integer i;
Standard_Real U;
myExtPC.Initialize((*((TheCurve*)myC)), mysample,
myintuinf, myintusup, mytolu, mytolf);
myExtPC.Initialize(mysample, myintuinf, myintusup, mytolu, mytolf);
myExtPC.Perform(P);
mydone = myExtPC.IsDone();
if (mydone) {
if (mydone)
{
Standard_Integer NbExt = myExtPC.NbExt();
for (i = 1; i <= NbExt; i++) {
for (i = 1; i <= NbExt; i++)
{
// Verification de la validite des parametres pour le cas trimme:
ThePOnC PC = myExtPC.Point(i);
U = PC.Parameter();
if (TheCurveTool::IsPeriodic(*((TheCurve*)myC))) {
if (TheCurveTool::IsPeriodic(*((TheCurve*)myC)))
{
U = ElCLib::InPeriod(U, myuinf, myuinf+TheCurveTool::Period(*((TheCurve*)myC)));
}
if ((U >= myuinf - mytolu) && (U <= myusup + mytolu)) {
if ((U >= myuinf - mytolu) && (U <= myusup + mytolu))
{
PC.SetValues(U, PC.Value());
mySqDist.Append(myExtPC.SquareDistance(i));
myismin.Append(myExtPC.IsMin(i));
@@ -384,4 +547,3 @@ void Extrema_GExtPC::TrimmedSquareDistances(Standard_Real& dist1,
P1 = Pf;
P2 = Pl;
}

View File

@@ -494,9 +494,16 @@ void ProjLib_ProjectedCurve::Load(const Handle(Adaptor3d_HCurve)& C)
Extrema_ExtPC anExtr(P, mySurface->BasisCurve()->Curve(), myTolerance);
if (anExtr.IsDone())
{
Standard_Integer anIndex = 1;
while (!anExtr.IsMin(anIndex) && anIndex < anExtr.NbExt()) anIndex++;
Vsingular[0] = anExtr.Point(anIndex).Parameter();
Standard_Real aMinDist = RealLast();
for(Standard_Integer anIdx = 1; anIdx <= anExtr.NbExt(); anIdx++)
{
if (anExtr.IsMin(anIdx) &&
anExtr.SquareDistance(anIdx) < aMinDist)
{
aMinDist = anExtr.SquareDistance(anIdx);
Vsingular[0] = anExtr.Point(anIdx).Parameter();
}
}
}
else
Vsingular[0] = ElCLib::Parameter(L, P);
@@ -513,9 +520,16 @@ void ProjLib_ProjectedCurve::Load(const Handle(Adaptor3d_HCurve)& C)
Extrema_ExtPC anExtr(P, mySurface->BasisCurve()->Curve(), myTolerance);
if (anExtr.IsDone())
{
Standard_Integer anIndex = 1;
while (!anExtr.IsMin(anIndex) && anIndex < anExtr.NbExt()) anIndex++;
Vsingular[1] = anExtr.Point(anIndex).Parameter();
Standard_Real aMinDist = RealLast();
for(Standard_Integer anIdx = 1; anIdx <= anExtr.NbExt(); anIdx++)
{
if (anExtr.IsMin(anIdx) &&
anExtr.SquareDistance(anIdx) < aMinDist)
{
aMinDist = anExtr.SquareDistance(anIdx);
Vsingular[1] = anExtr.Point(anIdx).Parameter();
}
}
}
else
Vsingular[1] = ElCLib::Parameter(L, P);

View File

@@ -232,16 +232,28 @@ Standard_Real ShapeAnalysis_Curve::ProjectAct(const Adaptor3d_Curve& C3D,
try {
OCC_CATCH_SIGNALS
Extrema_ExtPC myExtPC(P3D,C3D);
if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) ) {
Standard_Real dist2, dist2Min = myExtPC.SquareDistance(1);
Standard_Integer index = 1;
for ( Standard_Integer i = 2; i <= myExtPC.NbExt(); i++) {
Standard_Real dist2Min = RealLast() , dist2;
Standard_Integer index = 0;
if ( myExtPC.IsDone() && ( myExtPC.NbExt() > 0) )
{
for ( Standard_Integer i = 1; i <= myExtPC.NbExt(); i++)
{
if (!myExtPC.IsMin(i))
continue;
dist2 = myExtPC.SquareDistance(i);
if ( dist2 < dist2Min) { dist2Min = dist2; index = i; }
if ( dist2 < dist2Min)
{
dist2Min = dist2; index = i;
}
}
if (index != 0)
{
param = (myExtPC.Point(index)).Parameter();
proj = (myExtPC.Point(index)).Value();
OK = Standard_True;
}
param = (myExtPC.Point(index)).Parameter();
proj = (myExtPC.Point(index)).Value();
OK = Standard_True;
}
}
catch(Standard_Failure) {