]> OCCT Git - occt-copy.git/commitdiff
0030435: Improving performance of Approx_ComputeCLine
authorifv <ifv@opencascade.com>
Thu, 10 Jan 2019 10:07:01 +0000 (13:07 +0300)
committerifv <ifv@opencascade.com>
Mon, 22 Apr 2019 11:03:45 +0000 (14:03 +0300)
1. Approx_ComputeCLine.gxx, Approx_FitAndDivide.hxx, Approx_FitAndDivide2d.hxx, BRepFill_ComputeCLine.hxx
It is base modification, which allows improve performance of approximation with help of Approx_ComputeCLine. The main idea of improvement is using degree selection by inverse order - from maxdegree to mindegree. If tolerance for maxdegree is not reached, there is no sense to make approximation for current number of knots with lower degree, it is necessary to cut parametric interval.

2. ProjLib_ComputeApprox, ProjLib_ComputeApproxOnPolarSurface, ProjLib_ComputeApproxOnPolarSurface, ProjLib_ProjectOnPlane
It is additional modification of methods using Approx_ComputeCLine.
Mainly, modifications concern to more optimal choosing parameters for approximation algorithm.

3. BRepCheck_Face
Small improvement of method Intersect(...), which intersects two wires on face.

4. BRepTopAdaptor_FClass2d
Impovement of treatment infinitely narrow faces.

5. ChFi3d/ChFi3d_Builder_6.cxx
Small improvement, which forbids extension of singular boundary of surface.
It was TODO problem in tests/bugs/modalg_7/bug27711_3

6. IntTools_EdgeEdge.cxx
Improvement of performance for cases of searching common parts between line  and analytical curve

7. GeomliteTest_CurveCommands.cxx
Adding Draw command fitcurve. This command is analog of approxcurve, but uses Approx_FitAndDivide algorithm.
Mainly to have direct draw command for testing Approx_ComputeCLine.

8. Extrema_ExtElC.cxx

Treatment of case "infinite solutions" for extrema line-ellipse

9. Modification of some tests according to new behavior of algorithm.

10. tests/perf/moddata/bug30435
Test for new improved algorithm.

11. Implementation QAcommand OCC30435 in QABugs_20.cxx used in test bug30435

21 files changed:
src/Approx/Approx_ComputeCLine.gxx
src/Approx/Approx_FitAndDivide.hxx
src/Approx/Approx_FitAndDivide2d.hxx
src/BRepCheck/BRepCheck_Face.cxx
src/BRepFill/BRepFill_ComputeCLine.hxx
src/BRepTopAdaptor/BRepTopAdaptor_FClass2d.cxx
src/ChFi3d/ChFi3d_Builder_6.cxx
src/Extrema/Extrema_ExtElC.cxx
src/GeomliteTest/GeomliteTest_CurveCommands.cxx
src/IntTools/IntTools_EdgeEdge.cxx
src/ProjLib/ProjLib_ComputeApprox.cxx
src/ProjLib/ProjLib_ComputeApproxOnPolarSurface.cxx
src/ProjLib/ProjLib_ComputeApproxOnPolarSurface.hxx
src/ProjLib/ProjLib_ProjectOnPlane.cxx
src/QABugs/QABugs_20.cxx
tests/bugs/mesh/bug30008_2
tests/bugs/modalg_7/bug27711_3
tests/de/step_4/D9
tests/de/step_4/E1
tests/lowalgos/intss/bug27263
tests/perf/moddata/bug30435 [new file with mode: 0644]

index d13c01e6e31b523673a27cab2e77276f4202cc12..c9e7ed838d8b5ebc3d62def7c42210174316cfbd 100644 (file)
@@ -25,6 +25,8 @@
 #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
@@ -50,7 +52,8 @@ const AppParCurves_Constraint LastC)
   mycut = cutting;
   myfirstC = FirstC;
   mylastC = LastC;
-  myMaxSegments = IntegerLast();
+  myMaxSegments = MAXSEGM;
+  myInvOrder = Standard_True;
   alldone = Standard_False;
   Perform(Line);
 }
@@ -77,7 +80,8 @@ const AppParCurves_Constraint LastC)
   mycut = cutting;
   myfirstC = FirstC;
   mylastC = LastC;
-  myMaxSegments = IntegerLast();
+  myMaxSegments = MAXSEGM;
+  myInvOrder = Standard_True;
 }
 
 //=======================================================================
@@ -244,33 +248,117 @@ Standard_Boolean Approx_ComputeCLine::Compute(const MultiLine& Line,
 {
 
 
-  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++) {
-
-    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) {
+  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;
-        myMultiCurves.Append(LSquare.Value());
+        TheTol3d = aPrevTol3d;
+        TheTol2d = aPrevTol2d;
+        myMultiCurves.Append(aPrevCurve);
         myfirstparam.Append(Ufirst);
         mylastparam.Append(Ulast);
-        Tolers3d.Append(TheTol3d);
-        Tolers2d.Append(TheTol2d);
+        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;
 }
@@ -335,6 +423,15 @@ void Approx_ComputeCLine::SetMaxSegments(const Standard_Integer theMaxSegments)
   myMaxSegments = theMaxSegments;
 }
 
+//=======================================================================
+//function : SetInvOrder
+//purpose  : 
+//=======================================================================
+void Approx_ComputeCLine::SetInvOrder(const Standard_Boolean theInvOrder)
+{
+  myInvOrder = theInvOrder;
+}
+
 //=======================================================================
 //function : IsAllApproximated
 //purpose  : returns False if at a moment of the approximation,
index f33f83e243b710d6374a3f2827428dc4196333bc..552af14087abb0e848b0cf2dc3b21ce0e116a03c 100644 (file)
@@ -64,6 +64,12 @@ public:
   //! Changes the max number of segments, which is allowed for cutting.
   Standard_EXPORT void SetMaxSegments (const Standard_Integer theMaxSegments);
   
+  //! Set inverse order of degree selection:
+  //! if theInvOrdr = true, current degree is chosen by inverse order -
+  //! from maxdegree to mindegree.
+  //! By default inverse order is used.
+  Standard_EXPORT void SetInvOrder(const Standard_Boolean theInvOrder);
+
   //! returns False if at a moment of the approximation,
   //! the status NoApproximation has been sent by the user
   //! when more points were needed.
@@ -118,6 +124,7 @@ private:
   AppParCurves_Constraint myfirstC;
   AppParCurves_Constraint mylastC;
   Standard_Integer myMaxSegments;
+  Standard_Boolean myInvOrder;
 
 
 };
index 829bd82fcbeb6213f7df5e5171e13f0bee75927b..c1d4283b3e0baeb6d1cbc3558b0008a336036f74 100644 (file)
@@ -64,6 +64,12 @@ public:
   //! Changes the max number of segments, which is allowed for cutting.
   Standard_EXPORT void SetMaxSegments (const Standard_Integer theMaxSegments);
   
+  //! Set inverse order of degree selection:
+  //! if theInvOrdr = true, current degree is chosen by inverse order -
+  //! from maxdegree to mindegree.
+  //! By default inverse order is used.
+  Standard_EXPORT void SetInvOrder(const Standard_Boolean theInvOrder);
+
   //! returns False if at a moment of the approximation,
   //! the status NoApproximation has been sent by the user
   //! when more points were needed.
@@ -118,7 +124,7 @@ private:
   AppParCurves_Constraint myfirstC;
   AppParCurves_Constraint mylastC;
   Standard_Integer myMaxSegments;
-
+  Standard_Boolean myInvOrder;
 
 };
 
index fd500c5e53b93b97ed600a56772d02d7e0e6bf77..d185feb40903e7d6d4c22c3d348944ef287d6f0f 100644 (file)
@@ -685,7 +685,9 @@ static Standard_Boolean Intersect(const TopoDS_Wire& wir1,
                              for (Standard_Integer j = 1; j <= PntSeq.Length(); j++)
                                {
                                  Standard_Real tolv = BRep_Tool::Tolerance( TopoDS::Vertex(CommonVertices(j)) );
-                                 if (P.IsEqual( PntSeq(j), tolv ))
+                                  tolv += 1.e-8; //possible tolerance of intersection point
+                                  Standard_Real dd = P.SquareDistance(PntSeq(j));
+                                 if (dd <= tolv * tolv)
                                    {
                                      NbCoinc++;
                                      break;
index 5391c41aae696357dee9cf7d06f70675cc75affb..273515069aa9bd5ac4f0bc048119aaed9fc68119 100644 (file)
@@ -64,6 +64,12 @@ public:
   //! Changes the max number of segments, which is allowed for cutting.
   Standard_EXPORT void SetMaxSegments (const Standard_Integer theMaxSegments);
 
+  //! Set inverse order of degree selection:
+  //! if theInvOrdr = true, current degree is chosen by inverse order -
+  //! from maxdegree to mindegree.
+  //! By default inverse order is used.
+  Standard_EXPORT void SetInvOrder(const Standard_Boolean theInvOrder);
+
   //! returns False if at a moment of the approximation,
   //! the status NoApproximation has been sent by the user
   //! when more points were needed.
@@ -118,6 +124,7 @@ private:
   AppParCurves_Constraint myfirstC;
   AppParCurves_Constraint mylastC;
   Standard_Integer myMaxSegments;
+  Standard_Boolean myInvOrder;
 
 };
 
index 1ab9716eced4f4c636e1da88df717ef639a4a064..aa332b7c1c553ec5469816e6a310d2f366f69977 100644 (file)
@@ -105,6 +105,8 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace,const
   Umin = Vmin = 0.0; //RealLast();
   Umax = Vmax = -Umin;
 
+  Standard_Integer aNbE = 0;
+  Standard_Real eps = 1.e-10;
   Standard_Integer BadWire=0;
   for( FaceExplorer.Init(Face,TopAbs_WIRE); (FaceExplorer.More() && BadWire==0); FaceExplorer.Next() )
     {
@@ -118,6 +120,7 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace,const
 
       TopExp_Explorer Explorer;
       for( Explorer.Init(FaceExplorer.Current(),TopAbs_EDGE); Explorer.More(); Explorer.Next() ) NbEdges++;
+      aNbE = NbEdges;
         
       gp_Pnt Ancienpnt3d(0,0,0);
       Standard_Boolean Ancienpnt3dinitialise = Standard_False;
@@ -394,6 +397,15 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace,const
       
              //-- FlecheU*=10.0;
              //-- FlecheV*=10.0;
+              if (aNbE == 1 && FlecheU < eps && FlecheV < eps && Abs(square) < eps)
+              {
+                TabOrien.Append(1);
+              }
+              else
+              { 
+                TabOrien.Append(((square < 0.0)? 1 : 0));
+              }
+             
              if(FlecheU<Toluv) FlecheU = Toluv;
              if(FlecheV<Toluv) FlecheV = Toluv;
              //-- cout<<" U:"<<FlecheU<<" V:"<<FlecheV<<endl;
@@ -411,7 +423,6 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace,const
 //#endif
 //             } 
 //           else TabOrien.Append(((angle>0.0)? 1 : 0));
-             TabOrien.Append(((square < 0.0)? 1 : 0));
            }//if(nbpoints>3
          else
            { 
index a43192a558e34d63542647935977f1a21ef83950..58188b79016af40d4e92357be714124d43082ca1 100644 (file)
@@ -689,14 +689,36 @@ Standard_Boolean ChFi3d_Builder::StoreData(Handle(ChFiDS_SurfData)& Data,
   length2=Data->LastExtensionValue();
 
   Handle(Geom_BoundedSurface) aBndSurf = Surf;
-  if (length1 > Precision::Confusion())
-    GeomLib::ExtendSurfByLength(aBndSurf,length1,1,Standard_False,Standard_False);
-  if (length2 >  Precision::Confusion())
-    GeomLib::ExtendSurfByLength(aBndSurf,length2,1,Standard_False,Standard_True);
-  Surf = Handle(Geom_BSplineSurface)::DownCast (aBndSurf);
+  Standard_Boolean ext1 = Standard_False, ext2 = Standard_False;
+  Standard_Real eps = Max(tolget3d, 2. * Precision::Confusion());
+  if (length1 > eps)
+  {
+    gp_Pnt P11, P21;
+    P11 = Surf->Pole(1, 1);
+    P21 = Surf->Pole(Surf->NbUPoles(), 1);
+    if (P11.Distance(P21) > eps)
+    {
+      //to avoid extending surface with singular boundary
+      GeomLib::ExtendSurfByLength(aBndSurf, length1, 1, Standard_False, Standard_False);
+      ext1 = Standard_True;
+    }
+  }
+  if (length2 > eps)
+  {
+    gp_Pnt P12, P22;
+    P12 = Surf->Pole(1, Surf->NbVPoles());
+    P22 = Surf->Pole(Surf->NbUPoles(), Surf->NbVPoles());
+    if (P12.Distance(P22) > eps)
+    {
+      //to avoid extending surface with singular boundary
+      GeomLib::ExtendSurfByLength(aBndSurf, length2, 1, Standard_False, Standard_True);
+      ext2 = Standard_True;
+    }
+  }
+  Surf = Handle(Geom_BSplineSurface)::DownCast(aBndSurf);
 
   //Correction of surface on extremities
-  if (length1 <= Precision::Confusion())
+  if (!ext1)
   {
     gp_Pnt P11, P21;
     P11 = lin->StartPointOnFirst().Value();
@@ -704,7 +726,7 @@ Standard_Boolean ChFi3d_Builder::StoreData(Handle(ChFiDS_SurfData)& Data,
     Surf->SetPole(1, 1, P11);
     Surf->SetPole(Surf->NbUPoles(), 1, P21);
   }
-  if (length2 <= Precision::Confusion())
+  if (!ext2)
   {
     gp_Pnt P12, P22;
     P12 = lin->EndPointOnFirst().Value();
index 8c81128afaeaeba5f6e489b71d439957996d6d50..c3d08e2a980ecbc4a4bc867fdf7da68bb49b999a 100644 (file)
@@ -674,6 +674,15 @@ Method:
   //
   ExtremaExtElC_TrigonometricRoots Sol(A1,A2,A3,A4,A5,0.,M_PI+M_PI);
   if (!Sol.IsDone()) { return; }
+  //
+  if (Sol.InfiniteRoots()) {
+    myIsPar = Standard_True;
+    gp_Pnt aP = ElCLib::EllipseValue(0., C2.Position(), C2.MajorRadius(), C2.MinorRadius());
+    mySqDist[0] = C1.SquareDistance(aP);
+    myNbExt = 1;
+    myDone = Standard_True;
+    return;
+  }
 
 // Storage of solutions ...
   gp_Pnt P1,P2;
index 180bae2373602a75dd7078a8dd87df5b831d46cc..426d8d798100e1f46fc41c1bae112ade16128cc7 100644 (file)
 #include <Approx_CurvilinearParameter.hxx>
 #include <Approx_CurveOnSurface.hxx>
 #include <Geom_BSplineSurface.hxx>
+
+#include <AppCont_Function.hxx>
+#include <Adaptor3d_HCurve.hxx>
+#include <GeomAdaptor_HCurve.hxx>
+#include <Approx_FitAndDivide.hxx>
+#include <Convert_CompBezierCurvesToBSplineCurve.hxx>
+
 #ifdef _WIN32
 Standard_IMPORT Draw_Viewer dout;
 #endif
 
+//Class is used in fitcurve
+class CurveEvaluator : public AppCont_Function
+
+{
+
+public:
+  Handle(Adaptor3d_HCurve) myCurve;
+
+  CurveEvaluator(const Handle(Adaptor3d_HCurve)& C)
+    : myCurve(C)
+  {
+    myNbPnt = 1;
+    myNbPnt2d = 0;
+  }
+
+  Standard_Real FirstParameter() const
+  {
+    return myCurve->FirstParameter();
+  }
+
+  Standard_Real LastParameter() const
+  {
+    return myCurve->LastParameter();
+  }
+
+  Standard_Boolean Value(const Standard_Real   theT,
+    NCollection_Array1<gp_Pnt2d>& /*thePnt2d*/,
+    NCollection_Array1<gp_Pnt>&   thePnt) const
+  {
+    thePnt(1) = myCurve->Value(theT);
+    return Standard_True;
+  }
+
+  Standard_Boolean D1(const Standard_Real   theT,
+    NCollection_Array1<gp_Vec2d>& /*theVec2d*/,
+    NCollection_Array1<gp_Vec>&   theVec) const
+  {
+    gp_Pnt aDummyPnt;
+    myCurve->D1(theT, aDummyPnt, theVec(1));
+    return Standard_True;
+  }
+};
+
+
 //=======================================================================
 //function : anacurve
 //purpose  : 
@@ -1672,6 +1723,99 @@ static Standard_Integer approxcurve(Draw_Interpretor& di, Standard_Integer n, co
   return 0;
 }
 
+
+//=======================================================================
+//function : fitcurve
+//purpose  : 
+//=======================================================================
+
+static Standard_Integer fitcurve(Draw_Interpretor& di, Standard_Integer n, const char** a)
+{
+  if (n<3) return 1;
+
+  Handle(Geom_Curve) GC;
+  GC = DrawTrSurf::GetCurve(a[2]);
+  if (GC.IsNull())
+    return 1;
+
+  Standard_Integer Dmin = 3;
+  Standard_Integer Dmax = 14;
+  Standard_Real Tol3d = 1.e-5;
+  Standard_Boolean inverse = Standard_True;
+
+  if (n > 3)
+  {
+    Tol3d = Atof(a[3]);
+  }
+
+  if (n > 4)
+  {
+    Dmax = atoi(a[4]);
+  }
+
+  if (n > 5)
+  {
+    Standard_Integer inv = atoi(a[5]);
+    if (inv > 0)
+    {
+      inverse = Standard_True;
+    }
+    else
+    {
+      inverse = Standard_False;
+    }
+  }
+
+  Handle(GeomAdaptor_HCurve) aGAC = new GeomAdaptor_HCurve(GC);
+
+  CurveEvaluator aCE(aGAC);
+
+  Approx_FitAndDivide anAppro(Dmin, Dmax, Tol3d, 0., Standard_True);
+  anAppro.SetInvOrder(inverse);
+  anAppro.Perform(aCE);
+
+  if (!anAppro.IsAllApproximated())
+  {
+    di << "Approximation failed \n";
+    return 1;
+  }
+  Standard_Integer i;
+  Standard_Integer NbCurves = anAppro.NbMultiCurves();
+
+  Convert_CompBezierCurvesToBSplineCurve Conv;
+
+  Standard_Real tol3d, tol2d, tolreached = 0.;
+  for (i = 1; i <= NbCurves; i++) {
+    anAppro.Error(i, tol3d, tol2d);
+    tolreached = Max(tolreached, tol3d);
+    AppParCurves_MultiCurve MC = anAppro.Value(i);
+    TColgp_Array1OfPnt Poles(1, MC.Degree() + 1);
+    MC.Curve(1, Poles);
+    Conv.AddCurve(Poles);
+  }
+  Conv.Perform();
+  Standard_Integer NbPoles = Conv.NbPoles();
+  Standard_Integer NbKnots = Conv.NbKnots();
+
+  TColgp_Array1OfPnt      NewPoles(1, NbPoles);
+  TColStd_Array1OfReal    NewKnots(1, NbKnots);
+  TColStd_Array1OfInteger NewMults(1, NbKnots);
+
+  Conv.KnotsAndMults(NewKnots, NewMults);
+  Conv.Poles(NewPoles);
+
+  BSplCLib::Reparametrize(GC->FirstParameter(),
+    GC->LastParameter(),
+    NewKnots);
+  Handle(Geom_BSplineCurve) TheCurve = new Geom_BSplineCurve(NewPoles, NewKnots, NewMults, Conv.Degree());
+
+  DrawTrSurf::Set(a[1], TheCurve);
+  di << a[1] << ": tolreached = " << tolreached << "\n";
+
+  return 0;
+
+}
+
 //=======================================================================
 //function : newbspline
 //purpose  : reduce the multiplicity of the knots to their minimum 
@@ -2060,6 +2204,8 @@ void  GeomliteTest::CurveCommands(Draw_Interpretor& theCommands)
                  __FILE__,
                  approxcurveonsurf,g);
 
+ theCommands.Add("fitcurve", "fitcurve result  curve [tol [maxdeg [inverse]]]", __FILE__, fitcurve, g);
+
  theCommands.Add("length", "length curve [Tol]", 
                  __FILE__,
                  length, g);
index 38c36465d7b45d93abd1d656aa7243bab8d3b496..78ef6ab78dc5d6a3bfe30d6fd704021f6ce4bf91 100644 (file)
@@ -35,6 +35,7 @@
 #include <IntTools_Tools.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Iterator.hxx>
+#include <BRepExtrema_DistShapeShape.hxx>
 
 static 
   void BndBuildBox(const BRepAdaptor_Curve& theBAC,
@@ -224,6 +225,24 @@ void IntTools_EdgeEdge::Perform()
     }
   }
   //
+  if ((myCurve1.GetType() <= GeomAbs_Parabola && myCurve2.GetType() <= GeomAbs_Parabola) &&
+      (myCurve1.GetType() == GeomAbs_Line || myCurve2.GetType() == GeomAbs_Line))
+  {
+    //Improvement of performance for cases of searching common parts between line  
+    //and analytical curve. This code allows to define that edges have no
+    //common parts more fast, then regular algorithm (FindSolution(...))
+    //Check minimal distance between edges
+    BRepExtrema_DistShapeShape  aMinDist(myEdge1, myEdge2, Extrema_ExtFlag_MIN);
+    if (aMinDist.IsDone())
+    {
+      Standard_Real d = aMinDist.Value();
+      if (d > 1.1 * myTol)
+      {
+        return;
+      }
+    }
+  }
+
   IntTools_SequenceOfRanges aRanges1, aRanges2;
   //
   //3.2. Find ranges containig solutions
index 50909981873c6f32c768086771e627261b4d8612..e71fe844a696f9b4790f1950d8c1d4b3051dd74f 100644 (file)
@@ -1011,6 +1011,15 @@ void ProjLib_ComputeApprox::Perform
                                 (CType != GeomAbs_OtherCurve)     ;
 
   Standard_Boolean simplecase = SurfIsAnal && CurvIsAnal;
+  if (CType == GeomAbs_BSplineCurve || CType == GeomAbs_BezierCurve)
+  {
+    Standard_Integer aNbKnots = 1;
+    if (CType == GeomAbs_BSplineCurve)
+    {
+      aNbKnots = C->NbKnots();
+    }
+    simplecase = simplecase && C->Degree() <= 2 && aNbKnots <= 2;
+  }
 
   if (CType == GeomAbs_BSplineCurve &&
       SType == GeomAbs_Plane ) {
@@ -1111,12 +1120,12 @@ void ProjLib_ComputeApprox::Perform
 #endif    
 
 //-----------
-    Standard_Integer Deg1 = 8, Deg2;
-    if(simplecase) {
-      Deg2 = 10; 
+    Standard_Integer Deg1 = 5, Deg2;
+    if (simplecase) {
+      Deg2 = 8;
     }
     else {
-      Deg2 = 12; 
+      Deg2 = 10;
     }
     if(myDegMin > 0)
     {
@@ -1188,6 +1197,10 @@ void ProjLib_ComputeApprox::Perform
                               C->LastParameter(),
                               NewKnots);
 
+      // Set NewKnots(NbKnots) exactly C->LastParameter()
+      // to avoid problems if trim is used.
+      NewKnots(NbKnots) = C->LastParameter();
+
       // il faut recadrer les poles de debut et de fin:
       // ( Car pour les problemes de couture, on a du ouvrir l`intervalle
       // de definition de la courbe.)
index c104aa09ee32a410583b3ef091035cbde6651091..14a5f986162324899cf4a039eb4c8e2318e330e6 100644 (file)
@@ -482,7 +482,8 @@ ProjLib_ComputeApproxOnPolarSurface::ProjLib_ComputeApproxOnPolarSurface()
   myDegMin(-1), myDegMax(-1),
   myMaxSegments(-1),
   myMaxDist(-1.),
-  myBndPnt(AppParCurves_TangencyPoint)
+  myBndPnt(AppParCurves_TangencyPoint),
+  myDist(0.)
 {
 }
 
@@ -502,7 +503,8 @@ ProjLib_ComputeApproxOnPolarSurface::ProjLib_ComputeApproxOnPolarSurface
   myDegMin(-1), myDegMax(-1),
   myMaxSegments(-1),
   myMaxDist(-1.),
-  myBndPnt(AppParCurves_TangencyPoint)
+  myBndPnt(AppParCurves_TangencyPoint),
+  myDist(0.)
 {
   myBSpline = Perform(theInitialCurve2d, theCurve, theSurface);
 }
@@ -522,7 +524,8 @@ ProjLib_ComputeApproxOnPolarSurface::ProjLib_ComputeApproxOnPolarSurface
   myDegMin(-1), myDegMax(-1),
   myMaxSegments(-1),
   myMaxDist(-1.),
-  myBndPnt(AppParCurves_TangencyPoint)
+  myBndPnt(AppParCurves_TangencyPoint),
+  myDist(0.)
 {
   const Handle(Adaptor2d_HCurve2d) anInitCurve2d;
   myBSpline = Perform(anInitCurve2d, theCurve, theSurface);  
@@ -545,7 +548,8 @@ ProjLib_ComputeApproxOnPolarSurface::ProjLib_ComputeApproxOnPolarSurface
   myDegMin(-1), myDegMax(-1),
   myMaxSegments(-1),
   myMaxDist(-1.),
-  myBndPnt(AppParCurves_TangencyPoint)
+  myBndPnt(AppParCurves_TangencyPoint),
+  myDist(0.)
 {
   // InitialCurve2d and InitialCurve2dBis are two pcurves of the sewing 
   Handle(Geom2d_BSplineCurve) bsc =
@@ -1079,6 +1083,7 @@ Handle(Adaptor2d_HCurve2d)
   else {
     myProjIsDone = Standard_False;
     Standard_Real Dist2Min = 1.e+200, u = 0., v = 0.;
+    myDist = 0.;
     gp_Pnt pntproj;
 
     TColgp_SequenceOfPnt2d Sols;
@@ -1253,7 +1258,7 @@ Handle(Adaptor2d_HCurve2d)
       // U0 and V0 are the points in the initialized period 
       // (period with u and v),
       // U1 and V1 are the points for construction of poles
-
+      myDist = Dist2Min;
       for ( i = 2 ; i <= NbOfPnts ; i++) 
        if(myProjIsDone) {
          myProjIsDone = Standard_False;
@@ -1267,6 +1272,10 @@ Handle(Adaptor2d_HCurve2d)
            if (aLocateExtPS.SquareDistance() < DistTol3d2)
             {  //OCC217
               //if (aLocateExtPS.SquareDistance() < Tol3d * Tol3d) {
+              if (aLocateExtPS.SquareDistance() > myDist)
+              {
+                myDist = aLocateExtPS.SquareDistance();
+              }
              (aLocateExtPS.Point()).Parameter(U0,V0);
              U1 = U0 + usens*uperiod;
              V1 = V0 + vsens*vperiod;
@@ -1291,6 +1300,10 @@ Handle(Adaptor2d_HCurve2d)
                 }
                 if (LocalMinSqDist < DistTol3d2)
                 {
+                  if (LocalMinSqDist > myDist)
+                  {
+                    myDist = LocalMinSqDist;
+                  }
                   Standard_Real LocalU, LocalV;
                   aGlobalExtr.Point(imin).Parameter(LocalU, LocalV);
                   if (uperiod > 0. && Abs(U0 - LocalU) >= uperiod/2.)
@@ -1363,6 +1376,10 @@ Handle(Adaptor2d_HCurve2d)
            if (locext.IsDone())
              if (locext.SquareDistance() < DistTol3d2) {  //OCC217
              //if (locext.SquareDistance() < Tol3d * Tol3d) {
+                if (locext.SquareDistance() > myDist)
+                {
+                  myDist = locext.SquareDistance();
+                }
                (locext.Point()).Parameter(u,v);
                if((aUsup - U0) > (U0 - aUinf)) 
                  usens--;
@@ -1390,7 +1407,11 @@ Handle(Adaptor2d_HCurve2d)
            if (locext.IsDone())
              if (locext.SquareDistance() < DistTol3d2) {  //OCC217
              //if (locext.SquareDistance() < Tol3d * Tol3d) {
-               (locext.Point()).Parameter(u,v);
+                if (locext.SquareDistance() > myDist)
+                {
+                  myDist = locext.SquareDistance();
+                }
+                (locext.Point()).Parameter(u, v);
                if((aVsup - V0) > (V0 - aVinf)) 
                  vsens--;
                else 
@@ -1419,7 +1440,11 @@ Handle(Adaptor2d_HCurve2d)
            if (locext.IsDone())
              if (locext.SquareDistance() < DistTol3d2) {
              //if (locext.SquareDistance() < Tol3d * Tol3d) {
-               (locext.Point()).Parameter(u,v);
+                if (locext.SquareDistance() > myDist)
+                {
+                  myDist = locext.SquareDistance();
+                }
+                (locext.Point()).Parameter(u, v);
                if((Usup - U0) > (U0 - Uinf)) 
                  usens--;
                else 
@@ -1447,7 +1472,11 @@ Handle(Adaptor2d_HCurve2d)
                }
              if (Dist2Min < DistTol3d2) {
              //if (Dist2Min < Tol3d * Tol3d) {
-               (ext.Point(aGoodValue)).Parameter(u,v);
+                if (Dist2Min > myDist)
+                {
+                  myDist = Dist2Min;
+                }
+                (ext.Point(aGoodValue)).Parameter(u, v);
                if(uperiod) {
                  if((U0 - u) > (2*uperiod/3)) {
                    usens++;
@@ -1862,8 +1891,18 @@ Handle(Geom2d_BSplineCurve)
     aLastC = myBndPnt;
   }
 
+  if (myDist > 10.*Tol3d)
+  {
+    aFistC = AppParCurves_PassPoint; 
+    aLastC = AppParCurves_PassPoint;
+  }
+
   Approx_FitAndDivide2d Fit(Deg1, Deg2, Tol3d, Tol2d, Standard_True, aFistC, aLastC);
   Fit.SetMaxSegments(aMaxSegments);
+  if (InitCurve2d->GetType() == GeomAbs_Line)
+  {
+    Fit.SetInvOrder(Standard_False);
+  }
   Fit.Perform(F);
 
   Standard_Real anOldTol2d = Tol2d;
@@ -1936,6 +1975,10 @@ Handle(Geom2d_BSplineCurve)
 
     Standard_Boolean OK = Standard_True;
     Standard_Real aSmoothTol = Max(Precision::Confusion(), aNewTol2d);
+    if (myBndPnt == AppParCurves_PassPoint)
+    {
+      aSmoothTol *= 10.;
+    }
     for (Standard_Integer ij = 2; ij < NbKnots; ij++) {
       OK = OK && Dummy->RemoveKnot(ij,MaxDeg-1, aSmoothTol);  
     }
index 3927f2759c55896e54bbfaf5d1f2fb1a1b71fac3..393c8c68db4b8b5fbe411d47ed59c1d00e92ca32 100644 (file)
@@ -142,7 +142,7 @@ private:
   Standard_Integer myMaxSegments;
   Standard_Real myMaxDist;
   AppParCurves_Constraint myBndPnt;
-
+  Standard_Real myDist;
 
 };
 
index 61375aa3ed789901e7e704745a7a6e88fda71dc0..b059fcadfab95268dd2ce86d52d303b7b2720ee1 100644 (file)
@@ -317,8 +317,14 @@ static void  PerformApprox (const Handle(Adaptor3d_HCurve)& C,
   Standard_Integer Deg1, Deg2;
   Deg1 = 8; Deg2 = 8;
   
-  Approx_FitAndDivide Fit(F,Deg1,Deg2,Precision::Approximation(),
+  Approx_FitAndDivide Fit(Deg1,Deg2,Precision::Approximation(),
                          Precision::PApproximation(),Standard_True);
+  Fit.SetMaxSegments(100);
+  Fit.Perform(F);
+  if (!Fit.IsAllApproximated())
+  {
+    return;
+  }
   Standard_Integer i;
   Standard_Integer NbCurves = Fit.NbMultiCurves();
   Standard_Integer MaxDeg = 0;
@@ -347,9 +353,8 @@ static void  PerformApprox (const Handle(Adaptor3d_HCurve)& C,
     MC.Curve(1, LocalPoles);
     
     //Augmentation eventuelle du degre
-    Standard_Integer Inc = MaxDeg - MC.Degree();
-    if ( Inc > 0) {
-      BSplCLib::IncreaseDegree(Inc, Poles, BSplCLib::NoWeights(),
+    if (MaxDeg > MC.Degree() ) {
+      BSplCLib::IncreaseDegree(MaxDeg, LocalPoles, BSplCLib::NoWeights(),
                               TempPoles, BSplCLib::NoWeights());
       //mise a jour des poles de la PCurve
       for (Standard_Integer j = 1 ; j <= MaxDeg + 1; j++) {
index 6d92a0e549d29a014aca79e5b82c08a30646f0d4..09653f6e70bd6bfa17f2ecf4c545f45034be2a36 100644 (file)
@@ -3098,6 +3098,132 @@ static Standard_Integer QAEndsWith(Draw_Interpretor& di, Standard_Integer n, con
   return 1;
 }
 
+//Class is used in OCC30435
+#include <AppCont_Function.hxx>
+#include <Adaptor3d_HCurve.hxx>
+class CurveEvaluator : public AppCont_Function
+
+{
+
+public:
+  Handle(Adaptor3d_HCurve) myCurve;
+
+  CurveEvaluator(const Handle(Adaptor3d_HCurve)& C)
+    : myCurve(C)
+  {
+    myNbPnt = 1;
+    myNbPnt2d = 0;
+  }
+
+  Standard_Real FirstParameter() const
+  {
+    return myCurve->FirstParameter();
+  }
+
+  Standard_Real LastParameter() const
+  {
+    return myCurve->LastParameter();
+  }
+
+  Standard_Boolean Value(const Standard_Real   theT,
+    NCollection_Array1<gp_Pnt2d>& /*thePnt2d*/,
+    NCollection_Array1<gp_Pnt>&   thePnt) const
+  {
+    thePnt(1) = myCurve->Value(theT);
+    return Standard_True;
+  }
+
+  Standard_Boolean D1(const Standard_Real   theT,
+    NCollection_Array1<gp_Vec2d>& /*theVec2d*/,
+    NCollection_Array1<gp_Vec>&   theVec) const
+  {
+    gp_Pnt aDummyPnt;
+    myCurve->D1(theT, aDummyPnt, theVec(1));
+    return Standard_True;
+  }
+};
+
+#include <GeomAdaptor_HCurve.hxx>
+#include <Approx_FitAndDivide.hxx>
+#include <Convert_CompBezierCurvesToBSplineCurve.hxx>
+static Standard_Integer OCC30435(Draw_Interpretor& di, Standard_Integer, const char** a)
+{
+
+  Handle(Geom_Curve) GC;
+  GC = DrawTrSurf::GetCurve(a[2]);
+  if (GC.IsNull())
+    return 1;
+
+  Standard_Integer Dmin = 3;
+  Standard_Integer Dmax = 12;
+  Standard_Real Tol3d = 1.e-7;
+  Standard_Boolean inverse = Standard_True;
+
+
+  Standard_Integer inv = atoi(a[3]);
+  if (inv > 0)
+  {
+    inverse = Standard_True;
+  }
+  else
+  {
+    inverse = Standard_False;
+  }
+
+  Standard_Integer maxit = atoi(a[4]);
+
+  Handle(GeomAdaptor_HCurve) aGAC = new GeomAdaptor_HCurve(GC);
+
+  CurveEvaluator aCE(aGAC);
+
+  Approx_FitAndDivide anAppro(Dmin, Dmax, Tol3d, 0., Standard_True);
+  anAppro.SetInvOrder(inverse);
+  Standard_Integer i;
+  for (i = 1; i <= maxit; ++i)
+    anAppro.Perform(aCE);
+
+  if (!anAppro.IsAllApproximated())
+  {
+    di << "Approximation failed \n";
+    return 1;
+  }
+  Standard_Integer NbCurves = anAppro.NbMultiCurves();
+
+  Convert_CompBezierCurvesToBSplineCurve Conv;
+
+  Standard_Real tol3d, tol2d, tolreached = 0.;
+  for (i = 1; i <= NbCurves; i++) {
+    anAppro.Error(i, tol3d, tol2d);
+    tolreached = Max(tolreached, tol3d);
+    AppParCurves_MultiCurve MC = anAppro.Value(i);
+    TColgp_Array1OfPnt Poles(1, MC.Degree() + 1);
+    MC.Curve(1, Poles);
+    Conv.AddCurve(Poles);
+  }
+  Conv.Perform();
+  Standard_Integer NbPoles = Conv.NbPoles();
+  Standard_Integer NbKnots = Conv.NbKnots();
+
+  TColgp_Array1OfPnt      NewPoles(1, NbPoles);
+  TColStd_Array1OfReal    NewKnots(1, NbKnots);
+  TColStd_Array1OfInteger NewMults(1, NbKnots);
+
+  Conv.KnotsAndMults(NewKnots, NewMults);
+  Conv.Poles(NewPoles);
+
+  BSplCLib::Reparametrize(GC->FirstParameter(),
+    GC->LastParameter(),
+    NewKnots);
+  Handle(Geom_BSplineCurve) TheCurve = new Geom_BSplineCurve(NewPoles, NewKnots, NewMults, Conv.Degree());
+
+  DrawTrSurf::Set(a[1], TheCurve);
+  di << a[1] << ": tolreached = " << tolreached << "\n";
+
+  return 0;
+
+}
+
+
 void QABugs::Commands_20(Draw_Interpretor& theCommands) {
   const char *group = "QABugs";
 
@@ -3138,6 +3264,7 @@ void QABugs::Commands_20(Draw_Interpretor& theCommands) {
   theCommands.Add("OCC29807", "OCC29807 surface1 surface2 u1 v1 u2 v2", __FILE__, OCC29807, group);
   theCommands.Add("OCC29311", "OCC29311 shape counter nbiter: check performance of OBB calculation", __FILE__, OCC29311, group);
   theCommands.Add("OCC30391", "OCC30391 result face LenBeforeUfirst LenAfterUlast LenBeforeVfirst LenAfterVlast", __FILE__, OCC30391, group);
+  theCommands.Add("OCC30435", "OCC30435 result curve inverse nbit", __FILE__, OCC30435, group);
 
   theCommands.Add("QAStartsWith",
                   "QAStartsWith string startstring",
index 7daf3f0f66214a258364c3a17a180ace020a86a5..e7997c15bcbf634b3a18102db9c7cdffe7e116cf 100644 (file)
@@ -19,7 +19,7 @@ nurbsconvert result result
 incmesh result 0.15 -a 20
 
 tricheck result
-checktrinfo result -tri 193 -nod 147 -defl 0.042090809832482222 -tol_abs_defl 1.0e-7
+checktrinfo result -tri 193 -nod 147 -defl 0.04209 -tol_abs_defl 1.0e-6
 
 vinit
 
index bf3a0afc64fe932f4a8a4b19588191c7f90d6c14..d76d1cd245ac531236d2c4f223f7072fc8de67d3 100644 (file)
@@ -1,6 +1,3 @@
-puts "TODO CR27711 Linux: Tcl Exception: tolerance ang : 0.01"
-puts "TODO CR27711 Linux: TEST INCOMPLETE"
-
 puts "========"
 puts "OCC27711"
 puts "========"
index b8243241136661ffef2aafb5e5b1e5c736c69d9e..8bc1f9c4504cc4924d607e8534074892e0808490 100644 (file)
@@ -6,11 +6,11 @@ set filename test-m020306-v1.stp
 
 set ref_data {
 DATA        : Faulties = 0  ( 0 )  Warnings = 0  ( 0 )  Summary  = 0  ( 0 )
-TPSTAT      : Faulties = 0  ( 0 )  Warnings = 151  ( 114 )  Summary  = 151  ( 114 )
+TPSTAT      : Faulties = 0  ( 0 )  Warnings = 153  ( 114 )  Summary  = 153  ( 114 )
 CHECKSHAPE  : Wires    = 0  ( 0 )  Faces    = 0  ( 0 )  Shells   = 0  ( 0 )   Solids   = 0 ( 0 )
 NBSHAPES    : Solid    = 1  ( 1 )  Shell    = 1  ( 1 )  Face     = 742  ( 742 ) 
 STATSHAPE   : Solid    = 1  ( 1 )  Shell    = 1  ( 1 )  Face     = 742  ( 742 )   FreeWire = 0  ( 0 ) 
-TOLERANCE   : MaxTol   = 0.008481946718  (  0.01609778278 )  AvgTol   =  0.000132185171  (  0.0003164960473 )
+TOLERANCE   : MaxTol   = 0.008481946718  (  0.01167623167 )  AvgTol   =  0.000132472064  (  0.0003097606769 )
 LABELS      : N0Labels = 1  ( 1 )  N1Labels = 0  ( 0 )  N2Labels = 0  ( 0 )   TotalLabels = 1  ( 1 )   NameLabels = 1  ( 1 )   ColorLabels = 0  ( 0 )   LayerLabels = 0  ( 0 )
 PROPS       : Centroid = 0  ( 0 )  Volume   = 0  ( 0 )  Area     = 0  ( 0 )
 NCOLORS     : NColors  = 0  ( 0 )
index 449a5797b3505f45f0789eb3db16978605878b1d..fc7ab98fb30431c0a1fd3b3de3779017e18447f0 100644 (file)
@@ -7,7 +7,7 @@ TPSTAT      : Faulties = 0  ( 0 )  Warnings = 61  ( 157 )  Summary  = 61  ( 157
 CHECKSHAPE  : Wires    = 0  ( 0 )  Faces    = 0  ( 0 )  Shells   = 0  ( 0 )   Solids   = 0 ( 0 )
 NBSHAPES    : Solid    = 1  ( 1 )  Shell    = 1  ( 1 )  Face     = 956  ( 956 ) 
 STATSHAPE   : Solid    = 1  ( 1 )  Shell    = 1  ( 1 )  Face     = 956  ( 956 )   FreeWire = 0  ( 0 ) 
-TOLERANCE   : MaxTol   = 0.008481946718  (  0.01609778278 )  AvgTol   =  0.0001239210368  (  0.0003823229569 )
+TOLERANCE   : MaxTol   = 0.008481946718  (  0.05394823207 )  AvgTol   =  0.0001239210367  (  0.0004089750747 )
 LABELS      : N0Labels = 1  ( 1 )  N1Labels = 0  ( 0 )  N2Labels = 0  ( 0 )   TotalLabels = 1  ( 1 )   NameLabels = 1  ( 1 )   ColorLabels = 0  ( 0 )   LayerLabels = 0  ( 0 )
 PROPS       : Centroid = 0  ( 0 )  Volume   = 0  ( 0 )  Area     = 0  ( 0 )
 NCOLORS     : NColors  = 0  ( 0 )
index f6c316ede992a1d2c5590c6ec082e7983f76ca13..9471b1eb4db28f6a55bb4ad13ab6af1784dd236c 100644 (file)
@@ -7,7 +7,7 @@ puts ""
 #######################################################################
 
 set MaxTol 1.e-7
-set GoodNbCurv 1
+set GoodNbCurv 2
 
 restore [locate_data_file  bug27262_cmpd.brep] b
 explode b
@@ -30,5 +30,6 @@ if {${NbCurv} != ${GoodNbCurv}} {
 }
 
 checklength c_1 -l 2.9620641619623407
+checklength c_2 -l 3.1050603628884668
 
 checkview -screenshot -2d -path ${imagedir}/${test_image}.png
\ No newline at end of file
diff --git a/tests/perf/moddata/bug30435 b/tests/perf/moddata/bug30435
new file mode 100644 (file)
index 0000000..934405e
--- /dev/null
@@ -0,0 +1,46 @@
+puts "========"
+puts "BUG30435"
+puts "Improving performance of Approx_ComputeCLine"
+puts "========"
+puts ""
+
+pload QAcommands
+cone con 0 0 0 0 0 -1 1 0 0 -30 0
+2dbeziercurve b 4 0 0 15 15 35 -15 50 1.
+approxcurveonsurf cc b con  1.e-7 1 12 1000
+clear con
+clpoles cc
+
+set time0 ""
+set time1 ""
+
+dchrono t0 restart
+OCC30435 r0 cc 0 50
+dchrono t0 stop 
+set inf0 [dchrono t0 counter OCC30435] 
+
+regexp {COUNTER OCC30435: ([-0-9.+eE]+)} $inf0 full0 time0
+
+dchrono t1 restart
+OCC30435 r1 cc 1 50
+dchrono t1 stop
+set inf1 [dchrono t1 counter OCC30435_1] 
+regexp {COUNTER OCC30435_1: ([-0-9.+eE]+)} $inf1 full1 time1
+
+if { $time1 > $time0 } {
+    puts "Error : optimized algorithm works slowly then initial one"
+} else {
+    puts "Performance ratio is [expr $time0/$time1]"
+}
+
+clpoles r0
+clpoles r1
+smallview
+fit
+xwd $imagedir/${test_image}.png
+
+
+
+
+