0030940: BRepFilletAPI_MakeFillet algorithm fails on closed shell
[occt.git] / src / ChFi3d / ChFi3d.cxx
index 72d1728..9f0440c 100644 (file)
 #include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
+#include <BRepTools.hxx>
+#include <IntTools_Tools.hxx>
+
+static void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d);
+//
+
+//=======================================================================
+//function : DefineConnectType
+//purpose  : 
+//=======================================================================
+ChFiDS_TypeOfConcavity ChFi3d::DefineConnectType(const TopoDS_Edge&     E,
+                                                 const TopoDS_Face&     F1,
+                                                 const TopoDS_Face&     F2,
+                                                 const Standard_Real    SinTol,
+                                                 const Standard_Boolean CorrectPoint)
+{
+  const Handle(Geom_Surface)& S1 = BRep_Tool::Surface(F1);
+  const Handle(Geom_Surface)& S2 = BRep_Tool::Surface(F2);
+  //
+  Standard_Real   f,l;
+  Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
+  //For the case of seam edge
+  TopoDS_Edge EE = E;
+  if (F1.IsSame(F2))
+    EE.Reverse();
+  Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(EE,F2,f,l);
+
+  BRepAdaptor_Curve C(E);
+  f = C.FirstParameter();
+  l = C.LastParameter();
+//
+  Standard_Real ParOnC = 0.5*(f+l);
+  gp_Vec T1 = C.DN(ParOnC,1);
+  if (T1.SquareMagnitude() <= gp::Resolution())
+  {
+    ParOnC = IntTools_Tools::IntermediatePoint(f,l);
+    T1 = C.DN(ParOnC,1);
+  }
+  if (T1.SquareMagnitude() > gp::Resolution()) {
+    T1.Normalize();
+  }
+  
+  if (BRepTools::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
+    T1.Reverse();
+  }
+  if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
+
+  gp_Pnt2d P  = C1->Value(ParOnC);
+  gp_Pnt   P3;
+  gp_Vec   D1U,D1V;
+  
+  if(CorrectPoint) 
+    Correct2dPoint(F1, P);
+  //
+  S1->D1(P.X(),P.Y(),P3,D1U,D1V);
+  gp_Vec DN1(D1U^D1V);
+  if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
+  
+  P = C2->Value(ParOnC);
+  if(CorrectPoint) 
+    Correct2dPoint(F2, P);
+  S2->D1(P.X(),P.Y(),P3,D1U,D1V);
+  gp_Vec DN2(D1U^D1V);
+  if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
+
+  DN1.Normalize();
+  DN2.Normalize();
+
+  gp_Vec        ProVec     = DN1^DN2;
+  Standard_Real NormProVec = ProVec.Magnitude(); 
+
+  if (NormProVec < SinTol) {
+    // plane
+    if (DN1.Dot(DN2) > 0) {   
+      //Tangent
+      return ChFiDS_Tangential;
+    }
+    else  {                   
+      //Mixed not finished!
+#ifdef OCCT_DEBUG
+      std::cout <<" faces locally mixed"<<std::endl;
+#endif
+      return ChFiDS_Convex;
+    }
+  }
+  else {  
+    if (NormProVec > gp::Resolution())
+      ProVec /= NormProVec;
+    Standard_Real Prod  = T1.Dot(ProVec);
+    if (Prod > 0.) {       
+      //
+      return ChFiDS_Convex;
+    }
+    else {                       
+      //reenters
+      return ChFiDS_Concave;
+    }
+  }
+}
 
 //=======================================================================
 //function : ConcaveSide
@@ -290,3 +389,49 @@ Standard_Boolean  ChFi3d::SameSide(const TopAbs_Orientation Or,
   }
   return (o1 == o2);
 }
+
+//=======================================================================
+//function : Correct2dPoint
+//purpose  : 
+//=======================================================================
+void Correct2dPoint(const TopoDS_Face& theF, gp_Pnt2d& theP2d)
+{
+  BRepAdaptor_Surface aBAS(theF, Standard_False);
+  if (aBAS.GetType() < GeomAbs_BezierSurface) {
+    return;
+  }
+  //
+  const Standard_Real coeff = 0.01;
+  Standard_Real eps;
+  Standard_Real u1, u2, v1, v2;
+  //
+  aBAS.Initialize(theF, Standard_True);
+  u1 = aBAS.FirstUParameter();
+  u2 = aBAS.LastUParameter();
+  v1 = aBAS.FirstVParameter();
+  v2 = aBAS.LastVParameter();
+  if (!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
+  {
+    eps = Max(coeff*(u2 - u1), Precision::PConfusion());
+    if (Abs(theP2d.X() - u1) < eps)
+    {
+      theP2d.SetX(u1 + eps);
+    }
+    if (Abs(theP2d.X() - u2) < eps)
+    {
+      theP2d.SetX(u2 - eps);
+    }
+  }
+  if (!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
+  {
+    eps = Max(coeff*(v2 - v1), Precision::PConfusion());
+    if (Abs(theP2d.Y() - v1) < eps)
+    {
+      theP2d.SetY(v1 + eps);
+    }
+    if (Abs(theP2d.Y() - v2) < eps)
+    {
+      theP2d.SetY(v2 - eps);
+    }
+  }
+}