0028553: Incorrect result of the ShapeUpgrade_ShapeDivideContinuity algorithm
authormsv <msv@opencascade.com>
Tue, 14 Mar 2017 14:33:46 +0000 (17:33 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 23 Mar 2017 12:57:23 +0000 (15:57 +0300)
The cause of the bug was computation of incorrect UVBounds in the method ShapeAnalysis::GetFaceUVBounds. In this patch the computation of a box for a 2D curve in the method ShapeAnalysis_Curve::FillBndBox() has been improved taking into account intervals of C2 continuity.
Also the fix makes little extension of bounds when making the new surface in ShapeUpgrade_FaceDivide::SplitSurface(), so that all p-curves were fully inside.

Test case for issue CR28553

src/ShapeAnalysis/ShapeAnalysis_Curve.cxx
src/ShapeUpgrade/ShapeUpgrade_FaceDivide.cxx
tests/bugs/heal/bug28553 [new file with mode: 0644]

index 82d372c..fc6f276 100644 (file)
@@ -637,7 +637,8 @@ static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d,
                                           gp_Pnt2d &res)
 {
   Standard_Real prevpar;
-  for ( Standard_Integer i=0; i <10; i++ ) {
+  Standard_Integer nbOut = 0;
+  for (Standard_Integer i = 0; i <10; i++) {
     prevpar = par;
       
     gp_Vec2d D1, D2;
@@ -647,9 +648,19 @@ static Standard_Integer SearchForExtremum (const Handle(Geom2d_Curve)& C2d,
     
     par -= ( D1 * dir ) / Det;
     if ( Abs ( par - prevpar ) < Precision::PConfusion() ) return Standard_True;
-    
-    if ( First - par >= Precision::PConfusion() || 
-        par - Last  >= Precision::PConfusion() ) return Standard_False;
+
+    if (par < First)
+    {
+      if (nbOut++ > 2 || prevpar == First)
+        return Standard_False;
+      par = First;
+    }
+    if (par > Last)
+    {
+      if (nbOut++ > 2 || prevpar == Last)
+        return Standard_False;
+      par = Last;
+    }
   }
   return Standard_True;
 }
@@ -661,24 +672,46 @@ void ShapeAnalysis_Curve::FillBndBox (const Handle(Geom2d_Curve)& C2d,
                                      const Standard_Boolean Exact,
                                      Bnd_Box2d &Box) const
 {
-  Standard_Integer nseg = ( NPoints <2 ? 1 : NPoints-1 );
-  Standard_Real step = ( Last - First ) / nseg;
-  for ( Standard_Integer i=0; i <= nseg; i++ ) {
-    Standard_Real par = First + i * step;
-    gp_Pnt2d pnt = C2d->Value ( par );
-    Box.Add ( pnt );
-    if ( ! Exact ) continue;
-    
-    gp_Pnt2d pextr;
-    Standard_Real parextr = par;
-    if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
-                            gp_Vec2d(1,0), parextr, pextr ) ) {
-      Box.Add ( pextr );
+  if (!Exact) {
+    Standard_Integer nseg = (NPoints < 2 ? 1 : NPoints - 1);
+    Standard_Real step = (Last - First) / nseg;
+    for (Standard_Integer i = 0; i <= nseg; i++) {
+      Standard_Real par = First + i * step;
+      gp_Pnt2d pnt = C2d->Value(par);
+      Box.Add(pnt);
     }
-    parextr = par;
-    if ( SearchForExtremum ( C2d, Max(First,par-2.*step), Min(Last,par+2.*step),
-                            gp_Vec2d(0,1), parextr, pextr ) ) {
-      Box.Add ( pextr );
+    return;
+  }
+
+  // We should solve the task on intervals of C2 continuity.
+  Geom2dAdaptor_Curve anAC(C2d, First, Last);
+  Standard_Integer nbInt = anAC.NbIntervals(GeomAbs_C2);
+  // If we have only 1 interval then use input NPoints parameter to get samples.
+  Standard_Integer nbSamples = (nbInt < 2 ? NPoints - 1 : nbInt);
+  TColStd_Array1OfReal aParams(1, nbSamples + 1);
+  if (nbSamples == nbInt)
+    anAC.Intervals(aParams, GeomAbs_C2);
+  else {
+    Standard_Real step = (Last - First) / nbSamples;
+    for (Standard_Integer i = 0; i <= nbSamples; i++)
+      aParams(i+1) = First + i * step;
+  }
+  for (Standard_Integer i = 1; i <= nbSamples + 1; i++) {
+    Standard_Real aPar1 = aParams(i);
+    gp_Pnt2d aPnt = C2d->Value(aPar1);
+    Box.Add(aPnt);
+    if (i <= nbSamples) {
+      Standard_Real aPar2 = aParams(i + 1);
+      Standard_Real par = (aPar1 + aPar2) * 0.5;
+      gp_Pnt2d pextr;
+      Standard_Real parextr = par;
+      if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(1, 0), parextr, pextr)) {
+        Box.Add(pextr);
+      }
+      parextr = par;
+      if (SearchForExtremum(C2d, aPar1, aPar2, gp_Vec2d(0, 1), parextr, pextr)) {
+        Box.Add(pextr);
+      }
     }
   }
 }
index baaf0e0..9e6b94b 100644 (file)
@@ -132,7 +132,21 @@ Standard_Boolean ShapeUpgrade_FaceDivide::SplitSurface ()
   if(Precision::IsInfinite(Uf) || Precision::IsInfinite(Ul) ||
      Precision::IsInfinite(Vf) || Precision::IsInfinite(Vl))
     return Standard_False;
-       
+
+  // make little extension to ensure all pcurves fit inside new surface bounds
+  Standard_Real aSUf, aSUl, aSVf, aSVl;
+  surf->Bounds(aSUf, aSUl, aSVf, aSVl);
+  if (!surf->IsUPeriodic()) {
+    Standard_Real dU = (Ul - Uf) * 0.01;
+    if (Uf > aSUf) Uf -= Min(dU, Uf - aSUf);
+    if (Ul < aSUl) Ul += Min(dU, aSUl - Ul);
+  }
+  if (!surf->IsVPeriodic()) {
+    Standard_Real dV = (Vl - Vf) * 0.01;
+    if (Vf > aSVf) Vf -= Min(dV, Vf - aSVf);
+    if (Vl < aSVl) Vl += Min(dV, aSVl - Vl);
+  }
+
   SplitSurf->Init ( surf, Uf, Ul, Vf, Vl );
   SplitSurf->Perform(mySegmentMode);
 
diff --git a/tests/bugs/heal/bug28553 b/tests/bugs/heal/bug28553
new file mode 100644 (file)
index 0000000..f4a0324
--- /dev/null
@@ -0,0 +1,24 @@
+puts "======="
+puts "OCC28553"
+puts "======="
+puts ""
+##################################################
+# Incorrect result of the ShapeUpgrade_ShapeDivideContinuity algorithm
+##################################################
+
+restore [locate_data_file bug28553_sh.brep] f
+
+#Split shape
+DT_ShapeDivide r f
+
+explode r F
+mksurface s2 r_1
+don r_1 s2
+
+set fbnd [xbounds r_1]
+set v2f [lindex $fbnd 3]
+bounds s2 u1 u2 v1 v2
+
+if {$v2f > [dval v2]} {
+  puts "Error: result face bounds are out of surface ($v2f > [dval v2])"
+}