#include <Approx_ParametrizationType.hxx>
-#include Approx_MyLeastSquare_hxx
+#include <AppCont_LeastSquare.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <AppParCurves_Constraint.hxx>
#include <Approx_Status.hxx>
#include <Precision.hxx>
+const static Standard_Integer MAXSEGM = 1000;
+
//=======================================================================
//function : Approx_ComputeCLine
//purpose : The MultiLine <Line> will be approximated until tolerances
//=======================================================================
Approx_ComputeCLine::Approx_ComputeCLine
- (const MultiLine& Line,
- const Standard_Integer degreemin,
- const Standard_Integer degreemax,
- const Standard_Real Tolerance3d,
- const Standard_Real Tolerance2d,
- const Standard_Boolean cutting,
- const AppParCurves_Constraint FirstC,
- const AppParCurves_Constraint LastC)
+(const MultiLine& Line,
+const Standard_Integer degreemin,
+const Standard_Integer degreemax,
+const Standard_Real Tolerance3d,
+const Standard_Real Tolerance2d,
+const Standard_Boolean cutting,
+const AppParCurves_Constraint FirstC,
+const AppParCurves_Constraint LastC)
{
mydegremin = degreemin;
mydegremax = degreemax;
mycut = cutting;
myfirstC = FirstC;
mylastC = LastC;
+ myMaxSegments = MAXSEGM;
+ myInvOrder = Standard_True;
alldone = Standard_False;
Perform(Line);
}
//=======================================================================
Approx_ComputeCLine::Approx_ComputeCLine
- (const Standard_Integer degreemin,
- const Standard_Integer degreemax,
- const Standard_Real Tolerance3d,
- const Standard_Real Tolerance2d,
- const Standard_Boolean cutting,
- const AppParCurves_Constraint FirstC,
- const AppParCurves_Constraint LastC)
+(const Standard_Integer degreemin,
+const Standard_Integer degreemax,
+const Standard_Real Tolerance3d,
+const Standard_Real Tolerance2d,
+const Standard_Boolean cutting,
+const AppParCurves_Constraint FirstC,
+const AppParCurves_Constraint LastC)
{
alldone = Standard_False;
mydegremin = degreemin;
mycut = cutting;
myfirstC = FirstC;
mylastC = LastC;
+ myMaxSegments = MAXSEGM;
+ myInvOrder = Standard_True;
}
//=======================================================================
void Approx_ComputeCLine::Perform(const MultiLine& Line)
{
Standard_Real UFirst, ULast;
- Standard_Boolean Finish = Standard_False,
- begin = Standard_True, Ok = Standard_False;
+ Standard_Boolean Finish = Standard_False,
+ begin = Standard_True, Ok = Standard_False;
Standard_Real thetol3d = Precision::Confusion(), thetol2d = Precision::Confusion();
- UFirst = LineTool::FirstParameter(Line);
- ULast = LineTool::LastParameter(Line);
- Standard_Real TolU = (ULast-UFirst)*1.e-05;
- Standard_Real myfirstU = UFirst;
+ UFirst = Line.FirstParameter();
+ ULast = Line.LastParameter();
+ Standard_Real TolU = Max((ULast - UFirst)*1.e-03, Precision::Confusion());
+ Standard_Real myfirstU = UFirst;
Standard_Real mylastU = ULast;
+ Standard_Integer aMaxSegments = 0;
+ Standard_Integer aMaxSegments1 = myMaxSegments - 1;
+ Standard_Integer aNbCut = 0, aNbImp = 0, aNbComp = 10;
- if (!mycut) {
+ if (!mycut)
+ {
alldone = Compute(Line, UFirst, ULast, thetol3d, thetol2d);
- if (!alldone) {
+ if (!alldone)
+ {
tolreached = Standard_False;
myfirstparam.Append(UFirst);
mylastparam.Append(ULast);
Tolers2d.Append(currenttol2d);
}
}
- else {
+ else
+ {
// previous decision to be taken if we get worse with next cut (eap)
AppParCurves_MultiCurve KeptMultiCurve;
Standard_Real KeptUfirst = 0., KeptUlast = 0., KeptT3d = RealLast(), KeptT2d = 0.;
- Standard_Integer NbWorseDecis = 0, NbAllowedBadDecis = 10;
- while (!Finish) {
-
+ while (!Finish)
+ {
+
// Gestion du decoupage de la multiline pour approximer:
- if (!begin) {
- if (Ok) {
- // Calcul de la partie a approximer.
- myfirstU = mylastU;
- mylastU = ULast;
- if (Abs(ULast-myfirstU) <= RealEpsilon()) {
- Finish = Standard_True;
- alldone = Standard_True;
- return;
- }
- KeptT3d = RealLast(); KeptT2d = 0;
- NbWorseDecis = 0;
- }
- else {
- // keep best decison
- if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d)) {
- KeptMultiCurve = TheMultiCurve;
- KeptUfirst = myfirstU;
- KeptUlast = mylastU;
- KeptT3d = thetol3d;
- KeptT2d = thetol2d;
- }
-
- // cut an interval
- mylastU = (myfirstU + mylastU)/2;
- }
+ if (!begin)
+ {
+ if (Ok)
+ {
+ // Calcul de la partie a approximer.
+ myfirstU = mylastU;
+ mylastU = ULast;
+ aNbCut = 0;
+ aNbImp = 0;
+ if (Abs(ULast - myfirstU) <= RealEpsilon()
+ || aMaxSegments >= myMaxSegments)
+ {
+ Finish = Standard_True;
+ alldone = Standard_True;
+ return;
+ }
+ KeptT3d = RealLast(); KeptT2d = 0;
+ KeptUfirst = myfirstU;
+ KeptUlast = mylastU;
+ }
+ else
+ {
+ // keep best decison
+ if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
+ {
+ KeptMultiCurve = TheMultiCurve;
+ KeptUfirst = myfirstU;
+ KeptUlast = mylastU;
+ KeptT3d = thetol3d;
+ KeptT2d = thetol2d;
+ aNbImp++;
+ }
+
+ // cut an interval
+ mylastU = (myfirstU + mylastU) / 2;
+ aNbCut++;
+ }
}
- if (Abs(myfirstU-mylastU) <= TolU) /*break;*/ // pour ne pas planter
- NbAllowedBadDecis /= 2; // la station.
-
// Calcul des parametres sur ce nouvel intervalle.
Ok = Compute(Line, myfirstU, mylastU, thetol3d, thetol2d);
+ if (Ok)
+ {
+ aMaxSegments++;
+ }
//cout << myfirstU << " - " << mylastU << " tol : " << thetol3d << " " << thetol2d << endl;
-
+ Standard_Boolean aStopCutting = Standard_False;
+ if (aNbCut >= aNbComp)
+ {
+ if (aNbCut > aNbImp + 1)
+ {
+ aStopCutting = Standard_True;
+ }
+ aNbCut = 0;
+ aNbImp = 0;
+ }
// is new decision better?
- if ( !Ok && (thetol3d + thetol2d) > (KeptT3d + KeptT2d) )
+ if (!Ok && (Abs(myfirstU - mylastU) <= TolU || aMaxSegments >= aMaxSegments1 || aStopCutting ))
{
- NbWorseDecis++;
-
- if (NbWorseDecis > NbAllowedBadDecis) {
-
- Ok = Standard_True; // stop interval cutting, approx the rest part
- mylastU = KeptUlast;
-
- tolreached = Standard_False; // helas
- myMultiCurves.Append(KeptMultiCurve);
- Tolers3d.Append (KeptT3d);
- Tolers2d.Append (KeptT2d);
- myfirstparam.Append (KeptUfirst);
- mylastparam.Append (KeptUlast);
- }
+ Ok = Standard_True; // stop interval cutting, approx the rest part
+
+ if ((thetol3d + thetol2d) < (KeptT3d + KeptT2d))
+ {
+ KeptMultiCurve = TheMultiCurve;
+ KeptUfirst = myfirstU;
+ KeptUlast = mylastU;
+ KeptT3d = thetol3d;
+ KeptT2d = thetol2d;
+ }
+
+ mylastU = KeptUlast;
+
+ tolreached = Standard_False; // helas
+ myMultiCurves.Append(KeptMultiCurve);
+ aMaxSegments++;
+ Tolers3d.Append(KeptT3d);
+ Tolers2d.Append(KeptT2d);
+ myfirstparam.Append(KeptUfirst);
+ mylastparam.Append(KeptUlast);
}
begin = Standard_False;
//=======================================================================
Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
- const Standard_Real Ufirst,
- const Standard_Real Ulast,
- Standard_Real& TheTol3d,
- Standard_Real& TheTol2d)
+ const Standard_Real Ufirst,
+ const Standard_Real Ulast,
+ Standard_Real& TheTol3d,
+ Standard_Real& TheTol2d)
{
- Standard_Integer deg, NbPoints = 24;
+ const Standard_Integer NbPointsMax = 24;
+ const Standard_Real aMinRatio = 0.05;
+ const Standard_Integer aMaxDeg = 8;
+ //
+ Standard_Integer deg, NbPoints;
Standard_Boolean mydone;
Standard_Real Fv;
- for (deg = mydegremin; deg <= mydegremax; deg++) {
-
- AppParCurves_MultiCurve mySCU(deg+1);
- Approx_MyLeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC,
- deg, NbPoints);
- mydone = LSquare.IsDone();
- if (mydone) {
- LSquare.Error(Fv, TheTol3d, TheTol2d);
- if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
- mySCU = LSquare.Value();
- // Stockage de la multicurve approximee.
- tolreached = Standard_True;
- myMultiCurves.Append(mySCU);
- myfirstparam.Append(Ufirst);
- mylastparam.Append(Ulast);
- Tolers3d.Append(TheTol3d);
- Tolers2d.Append(TheTol2d);
- return Standard_True;
+ AppParCurves_MultiCurve aPrevCurve;
+ Standard_Real aPrevTol3d = RealLast(), aPrevTol2d = RealLast();
+ Standard_Boolean aPrevIsOk = Standard_False;
+ Standard_Boolean anInvOrder = myInvOrder;
+ if (anInvOrder && mydegremax > aMaxDeg)
+ {
+ if ((Ulast - Ufirst) / (Line.LastParameter() - Line.FirstParameter()) < aMinRatio)
+ {
+ anInvOrder = Standard_False;
+ }
+ }
+ if (anInvOrder)
+ {
+ for (deg = mydegremax; deg >= mydegremin; deg--) {
+ NbPoints = Min(2 * deg + 1, NbPointsMax);
+ AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
+ mydone = LSquare.IsDone();
+ if (mydone)
+ {
+ LSquare.Error(Fv, TheTol3d, TheTol2d);
+ if (TheTol3d <= mytol3d && TheTol2d <= mytol2d)
+ {
+ if (deg == mydegremin)
+ {
+ // Stockage de la multicurve approximee.
+ tolreached = Standard_True;
+ myMultiCurves.Append(LSquare.Value());
+ myfirstparam.Append(Ufirst);
+ mylastparam.Append(Ulast);
+ Tolers3d.Append(TheTol3d);
+ Tolers2d.Append(TheTol2d);
+ return Standard_True;
+ }
+ aPrevTol3d = TheTol3d;
+ aPrevTol2d = TheTol2d;
+ aPrevCurve = LSquare.Value();
+ aPrevIsOk = Standard_True;
+ continue;
+ }
+ else if (aPrevIsOk)
+ {
+ // Stockage de la multicurve approximee.
+ tolreached = Standard_True;
+ TheTol3d = aPrevTol3d;
+ TheTol2d = aPrevTol2d;
+ myMultiCurves.Append(aPrevCurve);
+ myfirstparam.Append(Ufirst);
+ mylastparam.Append(Ulast);
+ Tolers3d.Append(aPrevTol3d);
+ Tolers2d.Append(aPrevTol2d);
+ return Standard_True;
+ }
+ }
+ else if (aPrevIsOk)
+ {
+ // Stockage de la multicurve approximee.
+ tolreached = Standard_True;
+ TheTol3d = aPrevTol3d;
+ TheTol2d = aPrevTol2d;
+ myMultiCurves.Append(aPrevCurve);
+ myfirstparam.Append(Ufirst);
+ mylastparam.Append(Ulast);
+ Tolers3d.Append(aPrevTol3d);
+ Tolers2d.Append(aPrevTol2d);
+ return Standard_True;
+ }
+ if (!aPrevIsOk && deg == mydegremax)
+ {
+ TheMultiCurve = LSquare.Value();
+ currenttol3d = TheTol3d;
+ currenttol2d = TheTol2d;
+ aPrevTol3d = TheTol3d;
+ aPrevTol2d = TheTol2d;
+ aPrevCurve = TheMultiCurve;
+ break;
}
}
- if (deg == mydegremax) {
- TheMultiCurve = LSquare.Value();
- currenttol3d = TheTol3d;
- currenttol2d = TheTol2d;
+ }
+ else
+ {
+ for (deg = mydegremin; deg <= mydegremax; deg++) {
+ NbPoints = Min(2 * deg + 1, NbPointsMax);
+ AppCont_LeastSquare LSquare(Line, Ufirst, Ulast, myfirstC, mylastC, deg, NbPoints);
+ mydone = LSquare.IsDone();
+ if (mydone) {
+ LSquare.Error(Fv, TheTol3d, TheTol2d);
+ if (TheTol3d <= mytol3d && TheTol2d <= mytol2d) {
+ // Stockage de la multicurve approximee.
+ tolreached = Standard_True;
+ myMultiCurves.Append(LSquare.Value());
+ myfirstparam.Append(Ufirst);
+ mylastparam.Append(Ulast);
+ Tolers3d.Append(TheTol3d);
+ Tolers2d.Append(TheTol2d);
+ return Standard_True;
+ }
+ }
+ if (deg == mydegremax) {
+ TheMultiCurve = LSquare.Value();
+ currenttol3d = TheTol3d;
+ currenttol2d = TheTol2d;
+ }
}
-
}
return Standard_False;
}
//=======================================================================
void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
- Standard_Real& firstpar,
- Standard_Real& lastpar) const
+ Standard_Real& firstpar,
+ Standard_Real& lastpar) const
{
firstpar = myfirstparam.Value(Index);
- lastpar = mylastparam.Value(Index);
+ lastpar = mylastparam.Value(Index);
}
//=======================================================================
//=======================================================================
void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
- const Standard_Integer degreemax)
+ const Standard_Integer degreemax)
{
mydegremin = degreemin;
mydegremax = degreemax;
//=======================================================================
void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
- const Standard_Real Tolerance2d)
+ const Standard_Real Tolerance2d)
{
mytol3d = Tolerance3d;
mytol2d = Tolerance2d;
//=======================================================================
void Approx_ComputeCLine::SetConstraints(const AppParCurves_Constraint FirstC,
- const AppParCurves_Constraint LastC)
+ const AppParCurves_Constraint LastC)
{
myfirstC = FirstC;
- mylastC = LastC;
+ mylastC = LastC;
+}
+
+//=======================================================================
+//function : SetMaxSegments
+//purpose : Changes the max number of segments, which is allowed for cutting.
+//=======================================================================
+
+void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
+{
+ myMaxSegments = theMaxSegments;
+}
+
+//=======================================================================
+//function : SetInvOrder
+//purpose :
+//=======================================================================
+void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder)
+{
+ myInvOrder = theInvOrder;
}
//=======================================================================
//=======================================================================
void Approx_ComputeCLine::Error(const Standard_Integer Index,
- Standard_Real& tol3d,
- Standard_Real& tol2d) const
+ Standard_Real& tol3d,
+ Standard_Real& tol2d) const
{
tol3d = Tolers3d.Value(Index);
tol2d = Tolers2d.Value(Index);