0023994: GeomAPI_ExtremaCurveCurve class calculates wrong values
authorjgv <jgv@opencascade.com>
Thu, 4 Jul 2013 10:15:42 +0000 (14:15 +0400)
committerjgv <jgv@opencascade.com>
Thu, 4 Jul 2013 10:15:42 +0000 (14:15 +0400)
Adding test casefor this fix

src/Extrema/Extrema_CurveCache.cdl
src/Extrema/Extrema_CurveCache.gxx
src/Extrema/Extrema_CurveCache.lxx
src/Extrema/Extrema_GExtCC.gxx
src/Extrema/Extrema_GenExtCC.gxx
tests/bugs/moddata_3/bug23994 [new file with mode: 0755]

index 0539b6a..51623ba 100755 (executable)
@@ -27,6 +27,10 @@ inherits Transient from Standard
 
     ---Purpose:
 
+uses
+    Array1OfReal  from TColStd,
+    HArray1OfReal from TColStd
+
 raises NotDone from StdFail
 
 is
@@ -36,6 +40,12 @@ is
     Create (theC: Curve; theUFirst, theULast: Real; theNbSamples: Integer;
         theToCalculate: Boolean)returns mutable CurveCache from Extrema;
 
+    Create (theC: Curve; theUFirst, theULast: Real;
+           IntervalsCN: Array1OfReal from TColStd;
+           StartIndex, EndIndex: Integer;
+           Coeff: Real)
+    returns mutable CurveCache from Extrema;
+
     SetCurve (me: mutable; theC: Curve; theNbSamples: Integer;
         theToCalculate: Boolean);
     ---Purpose: Sets the \a theRank-th curve (1 or 2) and its parameters.
@@ -57,6 +67,12 @@ is
     ---Purpose: Returns True if the points array has already been calculated
     --          for specified curve and range
 
+    Parameters (me) returns HArray1OfReal from TColStd
+        raises  NotDone from StdFail;
+    ---C++: inline
+    ---C++: return const &
+    ---Purpose: Raises StdFail_NotDone if points have not yet been calculated.
+
     Points (me) returns ArrayOfPnt
         raises  NotDone from StdFail;
     ---C++: inline
@@ -95,6 +111,7 @@ fields
     myTrimFirst   : Real;
     myTrimLast    : Real;
     myNbSamples   : Integer;
+    myParamArray  : HArray1OfReal from TColStd;
     myPntArray    : ArrayOfPnt;
     myIsArrayValid: Boolean;
 
index dfef139..b9e0609 100755 (executable)
@@ -38,6 +38,64 @@ Extrema_CurveCache::Extrema_CurveCache(const Curve& theC,
 
 //=======================================================================
 //function : Extrema_CurveCache
+//purpose  : with sampling by knots and between them
+//=======================================================================
+
+Extrema_CurveCache::Extrema_CurveCache(const Curve& theC,
+                                       const Standard_Real theUFirst,
+                                       const Standard_Real theULast,
+                                       const TColStd_Array1OfReal& IntervalsCN,
+                                       const Standard_Integer StartIndex,
+                                       const Standard_Integer EndIndex,
+                                       const Standard_Real Coeff)
+{
+  myC = (Standard_Address)&theC;
+  myIsArrayValid = Standard_False;
+  myParamArray.Nullify();
+  myPntArray.Nullify();
+  
+  myTrimFirst = myFirst = theUFirst;
+  myTrimLast = myLast = theULast;
+
+  Standard_Integer Nbp = (Standard_Integer) (2 * Coeff);
+  myNbSamples = (EndIndex - StartIndex)*Nbp + 1;
+
+  const Standard_Integer aNbSTresh = 10000;
+  if (myNbSamples > aNbSTresh)
+  {
+    Nbp = aNbSTresh / (EndIndex - StartIndex);
+    myNbSamples = (EndIndex - StartIndex)*Nbp + 1;
+  }
+  
+  //Cache points
+  myParamArray = new TColStd_HArray1OfReal(1, myNbSamples);
+  myPntArray = new ArrayOfPnt (1, myNbSamples);
+  
+  const Curve& aCurve = *((Curve*)myC);
+  
+  Standard_Integer i, j, k = 1;
+  Standard_Real aPar;
+  for (i = StartIndex; i < EndIndex; i++)
+  {
+    Standard_Real delta = (IntervalsCN(i+1) - IntervalsCN(i)) / Nbp;
+    for (j = 0; j < Nbp; j++)
+    {
+      aPar = IntervalsCN(i) + j*delta;
+      myParamArray->SetValue(k, aPar);
+      myPntArray->SetValue(k++, aCurve.Value(aPar));
+    }
+  }
+  Standard_Real aDelta = (myTrimLast - myTrimFirst) / myNbSamples / 200.;
+  myParamArray->SetValue(1, myTrimFirst + aDelta);
+  myPntArray->SetValue(1, aCurve.Value(myTrimFirst + aDelta));
+  myParamArray->SetValue(myNbSamples, myTrimLast - aDelta);
+  myPntArray->SetValue(myNbSamples, aCurve.Value(myTrimLast - aDelta));
+
+  myIsArrayValid = Standard_True; //cache is available now
+}
+
+//=======================================================================
+//function : Extrema_CurveCache
 //purpose  : 
 //=======================================================================
 
@@ -58,6 +116,7 @@ void Extrema_CurveCache::SetCurve (const Curve& theC,
   myC = (Standard_Address)&theC;
   myNbSamples = theNbSamples;
   myIsArrayValid = Standard_False;
+  myParamArray.Nullify();
   myPntArray.Nullify();
   if (theToCalculate) {
     CalculatePoints();
@@ -99,6 +158,7 @@ void Extrema_CurveCache::SetRange (const Standard_Real theUFirst,
   }
 
   myIsArrayValid = Standard_False;
+  myParamArray.Nullify();
   myPntArray.Nullify();
   if (theToCalculate) {
     CalculatePoints();
@@ -124,11 +184,13 @@ void Extrema_CurveCache::CalculatePoints()
 
   //Cache points
 
+  myParamArray = new TColStd_HArray1OfReal(1, myNbSamples);
   myPntArray = new ArrayOfPnt (1, myNbSamples);
 
   Standard_Integer i;
   Standard_Real aPar;
   for (i = 1, aPar = aPar0; i <= myNbSamples; i++, aPar += aDelta) {
+    myParamArray->SetValue(i, aPar);
     myPntArray->SetValue (i, aCurve.Value (aPar));
   }
 
index 64f9811..f512a8d 100755 (executable)
@@ -20,6 +20,7 @@
 //            roman.lygin@gmail.com
 
 #include <StdFail_NotDone.hxx>
+#include <TColStd_HArray1OfReal.hxx>
 
 //=======================================================================
 //function : IsValid
@@ -32,6 +33,17 @@ inline Standard_Boolean Extrema_CurveCache::IsValid() const
 }
 
 //=======================================================================
+//function : Parameters
+//purpose  : 
+//=======================================================================
+
+inline const Handle(TColStd_HArray1OfReal)& Extrema_CurveCache::Parameters() const
+{
+  StdFail_NotDone_Raise_if (!myIsArrayValid, "Extrema_CurveCache::Parameters()")
+  return myParamArray;
+}
+
+//=======================================================================
 //function : Points
 //purpose  : 
 //=======================================================================
index e14a73b..fbd9719 100755 (executable)
@@ -272,8 +272,11 @@ void Extrema_GExtCC::Perform()
     //common case - use _GenExtCC
     //1. check and prepare caches
 
-    Standard_Integer i, aNbS[2] = {32, 32}, aNbInter[2] = {1, 1};
+    Standard_Integer i;
+    Standard_Integer aNbS[2] = {32, 32}, aNbInter[2] = {1, 1};
+    Standard_Real Coeff[2] = {1., 1.};
     Standard_Real rf = 0., rl = 0., LL[2] = {-1., -1.};
+    Standard_Boolean KnotSampling[2] = {Standard_False, Standard_False};
     for (i = 0; i < 2; i++) {
       TColStd_ListOfTransient& aCacheList = myCacheLists[i];
       if (aCacheList.IsEmpty()) {
@@ -288,10 +291,14 @@ void Extrema_GExtCC::Perform()
           aNbS[i] = aC.NbPoles() * 2;
           break;
         case GeomAbs_BSplineCurve:
+          if (aC.Degree() <= 3 &&
+              aC.NbKnots() > 2)
+            KnotSampling[i] = Standard_True;
+          
           aNbS[i] = aC.NbPoles() * 2;
-         rf = (Tool1::BSpline(*((Curve1*)myC[i])))->FirstParameter();
-         rl = (Tool1::BSpline(*((Curve1*)myC[i])))->LastParameter();
-         aNbS[i] = (Standard_Integer) ( aNbS[i] * ((mySup[i] - myInf[i]) / (rl - rf)) + 1 );
+          rf = (Tool1::BSpline(*((Curve1*)myC[i])))->FirstParameter();
+          rl = (Tool1::BSpline(*((Curve1*)myC[i])))->LastParameter();
+          aNbS[i] = (Standard_Integer) ( aNbS[i] * ((mySup[i] - myInf[i]) / (rl - rf)) + 1 );
         case GeomAbs_OtherCurve:
           //adjust number of sample points for B-Splines and Other curves
           aNbInter[i] = aC.NbIntervals (GeomAbs_C2);
@@ -314,10 +321,12 @@ void Extrema_GExtCC::Perform()
 
     if(LL[0] > 0. && LL[1] > 0.) {
       if(LL[0] > 4.*LL[1]) {
-       aNbS[0] = (Standard_Integer) ( aNbS[0] * LL[0]/LL[1]/2. );
+        Coeff[0] = LL[0]/LL[1]/2.;
+       aNbS[0]  = (Standard_Integer) ( aNbS[0] * Coeff[0] );
       }
       else if(LL[1] > 4.*LL[0]) {
-       aNbS[1] = (Standard_Integer) (aNbS[1] * LL[1]/LL[0]/2. );
+        Coeff[1] = LL[1]/LL[0]/2.;
+       aNbS[1]  = (Standard_Integer) (aNbS[1] * Coeff[1] );
       }
     }
     //modified by NIZNHY-PKV Tue Apr 17 10:01:32 2012f
@@ -337,16 +346,48 @@ void Extrema_GExtCC::Perform()
         //no caches, build them
         Curve1& aC = *(Curve1*)myC[i];
 
-        if (aC.GetType() >= GeomAbs_BSplineCurve) {
+        if (aC.GetType() >= GeomAbs_BSplineCurve)
+        {
           //can be multiple intervals, one cache per one C2 interval
           TColStd_Array1OfReal anArr (1, aNbInter[i] + 1);
           aC.Intervals (anArr, GeomAbs_C2);
-          for (Standard_Integer k = 1; k <= aNbInter[i]; k++) {
-            Handle(Extrema_CCache) aCache = new Extrema_CCache (aC,
-              anArr(k), anArr(k+1), aNbS[i], Standard_True);
-            aCacheList.Append (aCache);
+          
+          if (KnotSampling[i])
+          {
+            Standard_Integer NbIntervCN = aC.NbIntervals(GeomAbs_CN);
+            TColStd_Array1OfReal IntervalsCN(1, NbIntervCN + 1);
+            aC.Intervals(IntervalsCN, GeomAbs_CN);
+
+            Standard_Integer j = 1, start_j = 1, k;
+            Standard_Real NextKnot;
+            for (k = 1; k <= aNbInter[i]; k++)
+            {
+              do
+              {
+                NextKnot = IntervalsCN(j+1);
+                j++;
+              }
+              while (NextKnot != anArr(k+1));
+
+              Handle(Extrema_CCache) aCache =
+                new Extrema_CCache (aC, anArr(k), anArr(k+1),
+                                    IntervalsCN, start_j, j, Coeff[i]);
+              aCacheList.Append (aCache);
+
+              start_j = j;
+            }
           }
-        } else {
+          else
+          {
+            for (Standard_Integer k = 1; k <= aNbInter[i]; k++) {
+              Handle(Extrema_CCache) aCache =
+                new Extrema_CCache (aC, anArr(k), anArr(k+1), aNbS[i], Standard_True);
+              aCacheList.Append (aCache);
+            }
+          }
+        }
+        else
+        {
           //single interval from myInf[i] to mySup[i]
           Handle(Extrema_CCache) aCache = new Extrema_CCache (aC,
             myInf[i], mySup[i], aNbS[i], Standard_True);
index b24371c..a56e649 100755 (executable)
@@ -146,16 +146,6 @@ a- Constitution du tableau des distances (TbDist2(0,NbU+1,0,NbV+1)):
     aCache2->CalculatePoints();
 
 // Calcul des distances
-  //initialization of variables in the same way as in CalculatePoints()
-  Standard_Real PasU = aCache1->TrimLastParameter() - aCache1->TrimFirstParameter();
-  Standard_Real PasV = aCache2->TrimLastParameter() - aCache2->TrimFirstParameter();
-  Standard_Real U0 = PasU / aNbU / 100.;
-  Standard_Real V0 = PasV / aNbV / 100.;
-  PasU = (PasU - U0) / (aNbU - 1);
-  PasV = (PasV - V0) / (aNbV - 1);
-  U0 = aCache1->TrimFirstParameter() + (U0/2.);
-  V0 = aCache2->TrimFirstParameter() + (V0/2.);
-
   const Curve1& aCurve1 = *((Curve1*)(myF.CurvePtr (1)));
   const Curve2& aCurve2 = *((Curve1*)(myF.CurvePtr (2)));
   const Handle(ArrayOfPnt)& aPntArray1 = aCache1->Points();
@@ -207,6 +197,8 @@ b- Calcul des minima:
 //     - recherche d un minimum sur la grille
   Standard_Integer Nu, Nv;
   Standard_Real Dist2;
+  const Handle(TColStd_HArray1OfReal)& aParamArray1 = aCache1->Parameters();
+  const Handle(TColStd_HArray1OfReal)& aParamArray2 = aCache2->Parameters();
   for (NoU = 1; NoU <= aNbU; NoU++) {
     for (NoV = 1; NoV <= aNbV; NoV++) {
       if (TbSel(NoU,NoV) == 0) {
@@ -221,9 +213,9 @@ b- Calcul des minima:
            (TbDist2(NoU+1,NoV+1) >= Dist2)) {
 
 //     - calcul de l extremum sur la surface:
-         UV(1) = U0 + (NoU - 1) * PasU;
-         UV(2) = V0 + (NoV - 1) * PasV;
-
+          
+          UV(1) = aParamArray1->Value(NoU);
+          UV(2) = aParamArray2->Value(NoV);
 
          math_FunctionSetRoot S (myF,UV,Tol,UVinf,UVsup);
 
@@ -278,8 +270,9 @@ c- Calcul des maxima:
            (TbDist2(NoU+1,NoV+1) <= Dist2)) {
 
 //     - calcul de l extremum sur la surface:
-         UV(1) = U0 + (NoU - 1) * PasU;
-         UV(2) = V0 + (NoV - 1) * PasV;
+
+          UV(1) = aParamArray1->Value(NoU);
+          UV(2) = aParamArray2->Value(NoV);
 
          math_FunctionSetRoot S (myF,UV,Tol,UVinf,UVsup);
       
diff --git a/tests/bugs/moddata_3/bug23994 b/tests/bugs/moddata_3/bug23994
new file mode 100755 (executable)
index 0000000..9b1dd91
--- /dev/null
@@ -0,0 +1,42 @@
+puts "================"
+puts "OCC23994"
+puts "================"
+puts ""
+#######################################################################
+# GeomAPI_ExtremaCurveCurve class calculates wrong values
+#######################################################################
+
+set BugNumber CR23994
+
+pload XDE
+
+ReadStep D [locate_data_file bug23994_AirfoilRhomb_CalcDist_17_OP_Bell_Mouth_Roughing_shroud.stp]
+
+XCheckProps D
+
+XGetShape airflIntersctCrv D 0:1:1:1
+XGetShape rhombIntersctCrv D 0:1:1:2
+
+explode rhombIntersctCrv
+mkcurve rhomb rhombIntersctCrv_1
+
+explode airflIntersctCrv
+mkcurve airfl airflIntersctCrv_1
+
+extrema airfl rhomb
+
+if { [isdraw ext_1] } {
+   mkedge result ext_1
+   set length 9.09515
+} else {
+   puts "${BugNumber}: invalid result"
+}
+
+if { [isdraw ext_2] } {
+   mkedge result ext_2
+   set length 5.14563
+} else {
+   puts "${BugNumber}: invalid result"
+}
+
+set 2dviewer 1