0031404: Modeling Algorithms - BOP Fuse produces a self-interfering or a good shape...
[occt.git] / src / Approx / Approx_ComputeCLine.gxx
index 5973759..51eab1d 100644 (file)
 
 
 #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;
@@ -50,6 +52,8 @@ Approx_ComputeCLine::Approx_ComputeCLine
   mycut = cutting;
   myfirstC = FirstC;
   mylastC = LastC;
+  myMaxSegments = MAXSEGM;
+  myInvOrder = Standard_True;
   alldone = Standard_False;
   Perform(Line);
 }
@@ -60,13 +64,13 @@ Approx_ComputeCLine::Approx_ComputeCLine
 //=======================================================================
 
 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;
@@ -76,6 +80,8 @@ Approx_ComputeCLine::Approx_ComputeCLine
   mycut = cutting;
   myfirstC = FirstC;
   mylastC = LastC;
+  myMaxSegments = MAXSEGM;
+  myInvOrder = Standard_True;
 }
 
 //=======================================================================
@@ -86,18 +92,23 @@ Approx_ComputeCLine::Approx_ComputeCLine
 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);
@@ -106,69 +117,97 @@ void Approx_ComputeCLine::Perform(const MultiLine& Line)
       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;
@@ -204,43 +243,124 @@ const
 //=======================================================================
 
 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;
 }
@@ -252,11 +372,11 @@ Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
 //=======================================================================
 
 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);
 }
 
 //=======================================================================
@@ -265,7 +385,7 @@ void Approx_ComputeCLine::Parameters(const Standard_Integer Index,
 //=======================================================================
 
 void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
-                                    const Standard_Integer degreemax)
+  const Standard_Integer degreemax)
 {
   mydegremin = degreemin;
   mydegremax = degreemax;
@@ -277,7 +397,7 @@ void Approx_ComputeCLine::SetDegrees(const Standard_Integer degreemin,
 //=======================================================================
 
 void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
-                                      const Standard_Real Tolerance2d)
+  const Standard_Real Tolerance2d)
 {
   mytol3d = Tolerance3d;
   mytol2d = Tolerance2d;
@@ -289,10 +409,29 @@ void Approx_ComputeCLine::SetTolerances(const Standard_Real Tolerance3d,
 //=======================================================================
 
 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;
 }
 
 //=======================================================================
@@ -323,8 +462,8 @@ const {
 //=======================================================================
 
 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);