Salome HOME
Rewrite local function ModifySurface of BlockFix_SphereSpaceModifier
authorjgv <jgv@opencascade.com>
Wed, 28 Apr 2021 22:10:38 +0000 (01:10 +0300)
committerjfa <jfa@opencascade.com>
Mon, 6 Sep 2021 08:28:04 +0000 (11:28 +0300)
src/BlockFix/BlockFix_SphereSpaceModifier.cxx

index fa86224076f79c00fd4ddeb40a0e1fc0e1e87d8b..5847d30e58d3dd24880fa8dcf99f8ae6c65d200e 100644 (file)
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Vertex.hxx>
+#include <TopoDS_Iterator.hxx>
 
 #include <BRep_Tool.hxx>
 #include <BRep_Builder.hxx>
+#include <BRepTools.hxx>
+#include <BRepAdaptor_Curve2d.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
 
-#include <BRepGProp.hxx>
-#include <GProp_GProps.hxx>
-
+#include <ElSLib.hxx>
+#include <Geom_Circle.hxx>
+#include <Geom_TrimmedCurve.hxx>
 #include <Geom_SphericalSurface.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
 
@@ -87,64 +91,145 @@ void BlockFix_SphereSpaceModifier::SetTolerance(const Standard_Real Tol)
 //function : NewSurface
 //purpose  :
 //=======================================================================
-static Standard_Boolean ModifySurface(const TopoDS_Face& aFace,
-                                      const Handle(Geom_Surface)& aSurface,
-                                      Handle(Geom_Surface)& aNewSurface)
+static Standard_Boolean ModifySurface(const TopoDS_Face&          theFace,
+                                      const Handle(Geom_Surface)& theSurface,
+                                      Handle(Geom_Surface)&       theNewSurface)
 {
-  Handle(Geom_Surface) S = aSurface;
-  if(S->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
+  TopoDS_Face aFace = theFace;
+  aFace.Orientation (TopAbs_FORWARD);
+
+  Handle(Geom_Surface) aNewSurface;
+  
+  Handle(Geom_Surface) aSurf = theSurface;
+  if (aSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
     Handle(Geom_RectangularTrimmedSurface) RTS =
-      Handle(Geom_RectangularTrimmedSurface)::DownCast(S);
-    S = RTS->BasisSurface();
+      Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurf);
+    aSurf = RTS->BasisSurface();
   }
 
-  if(S->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) {
+  if (aSurf->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) {
     Standard_Real Umin, Umax, Vmin, Vmax;
-    ShapeAnalysis::GetFaceUVBounds(aFace,Umin, Umax, Vmin, Vmax);
+    ShapeAnalysis::GetFaceUVBounds (aFace, Umin, Umax, Vmin, Vmax);
     Standard_Real PI2 = M_PI/2.;
-    if(Vmax > PI2 - Precision::PConfusion() || Vmin < -PI2+::Precision::PConfusion()) {
-      Handle(Geom_SphericalSurface) aSphere = Handle(Geom_SphericalSurface)::DownCast(S);
-      gp_Sphere sp = aSphere->Sphere();
-      //modified by jgv, 12.11.2012 for issue 21777//
-      Standard_Real Radius = sp.Radius();
-      Standard_Real HalfArea = 2.*M_PI*Radius*Radius;
-      GProp_GProps Properties;
-      BRepGProp::SurfaceProperties(aFace, Properties);
-      Standard_Real anArea = Properties.Mass();
-      Standard_Real AreaTol = Radius*Radius*1.e-6;
-      if (anArea > HalfArea - AreaTol) //no chance to avoid singularity
-        return Standard_False;
-      ///////////////////////////////////////////////
-      gp_Ax3 ax3 = sp.Position();
-      if(Abs(Vmax-Vmin) < PI2) {
-        gp_Ax3 axnew3(ax3.Axis().Location(), ax3.Direction()^ax3.XDirection(),ax3.XDirection());
-        sp.SetPosition(axnew3);
-        Handle(Geom_SphericalSurface) aNewSphere = new Geom_SphericalSurface(sp);
-        aNewSurface = aNewSphere;
-        return Standard_True;
-      }
-      else {
-        gp_Pnt PC = ax3.Location();
-        Standard_Real Vpar;
-        if(fabs(PI2-Vmax)>fabs(-PI2-Vmin))
-          Vpar = (PI2+Vmax)/2.;
-        else
-          Vpar = (-PI2+Vmin)/2.;
-        Standard_Real Upar = (Umin+Umax)/2.;;
-        gp_Pnt PN,PX;
-        S->D0(Upar,Vpar,PN);
-        S->D0(Upar+PI2,0.,PX);
-        gp_Dir newNorm(gp_Vec(PC,PN));
-        gp_Dir newDirX(gp_Vec(PC,PX));
-        gp_Ax3 axnew3(ax3.Axis().Location(), newNorm, newDirX);
-        sp.SetPosition(axnew3);
-        Handle(Geom_SphericalSurface) aNewSphere = new Geom_SphericalSurface(sp);
-        aNewSurface = aNewSphere;
-        return Standard_True;
-      }
-    }
+    Handle(Geom_SphericalSurface) aSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf);
+    gp_Sphere sp = aSphere->Sphere();
+    Standard_Real Radius = sp.Radius();
+    gp_Ax3 ax3 = sp.Position();
+    gp_Pnt aCentre = sp.Location();
+    
+    TopoDS_Wire aWire = BRepTools::OuterWire (aFace);
+    BRepTopAdaptor_FClass2d aClassifier (aFace, Precision::PConfusion());
+    TopTools_MapOfShape aEmap;
+    const Standard_Real anOffsetValue = 0.01*M_PI;
+    for (Standard_Integer ii = 1; ii <= 2; ii++)
+    {
+      TopoDS_Iterator itw (aWire);
+      for (; itw.More(); itw.Next())
+      {
+        const TopoDS_Edge& anEdge = TopoDS::Edge (itw.Value());
+        if (aEmap.Contains (anEdge) ||
+            anEdge.Orientation() == TopAbs_INTERNAL ||
+            anEdge.Orientation() == TopAbs_EXTERNAL ||
+            BRep_Tool::Degenerated (anEdge) ||
+            BRepTools::IsReallyClosed (anEdge, aFace))
+          continue;
+        
+        BRepAdaptor_Curve2d aBAcurve2d (anEdge, aFace);
+        GeomAbs_CurveType aType = aBAcurve2d.GetType();
+        if (ii == 1 && aType == GeomAbs_Line) //first pass: consider only curvilinear edges
+          continue;
+        
+        Standard_Real aMidPar = (aBAcurve2d.FirstParameter() + aBAcurve2d.LastParameter())/2;
+        gp_Pnt2d aMidP2d;
+        gp_Vec2d aTangent;
+        aBAcurve2d.D1 (aMidPar, aMidP2d, aTangent);
+        if (anEdge.Orientation() == TopAbs_REVERSED)
+          aTangent.Reverse();
+        
+        aTangent.Normalize();
+        gp_Vec2d aNormal (aTangent.Y(), -aTangent.X());
+        aNormal *= anOffsetValue;
+        gp_Pnt2d anUpperPole = aMidP2d.Translated (aNormal);
+        if (anUpperPole.Y() < -PI2 || anUpperPole.Y() > PI2)
+        {
+          aEmap.Add(anEdge);
+          continue;
+        }
+        if (anUpperPole.X() < 0.)
+          anUpperPole.SetX (anUpperPole.X() + 2.*M_PI);
+        else if (anUpperPole.X() > 2.*M_PI)
+          anUpperPole.SetX (anUpperPole.X() - 2.*M_PI);
+        
+        TopAbs_State aStatus = aClassifier.Perform (anUpperPole);
+        if (aStatus != TopAbs_OUT)
+        {
+          aEmap.Add(anEdge);
+          continue;
+        }
+        
+        gp_Pnt anUpperPole3d = aSphere->Value (anUpperPole.X(), anUpperPole.Y());
+        gp_Vec aVec (aCentre, anUpperPole3d);
+        aVec.Reverse();
+        gp_Pnt aLowerPole3d = aCentre.Translated (aVec);
+        Standard_Real aU, aV;
+        ElSLib::Parameters (sp, aLowerPole3d, aU, aV);
+        gp_Pnt2d aLowerPole (aU, aV);
+        aStatus = aClassifier.Perform (aLowerPole);
+        if (aStatus != TopAbs_OUT)
+        {
+          aEmap.Add(anEdge);
+          continue;
+        }
+        
+        //Build a meridian
+        gp_Vec anUp (aCentre, anUpperPole3d);
+        anUp.Normalize();
+        gp_Pnt aMidPnt = aSphere->Value (aMidP2d.X(), aMidP2d.Y());
+        gp_Vec aMidOnEdge (aCentre, aMidPnt);
+        aMidOnEdge.Normalize();
+        gp_Vec AxisOfCircle = anUp ^ aMidOnEdge;
+        gp_Vec XDirOfCircle = anUp ^ AxisOfCircle;
+        gp_Ax2 anAxis (aCentre, AxisOfCircle, XDirOfCircle);
+        Handle(Geom_Circle) aCircle = new Geom_Circle (anAxis, Radius);
+        Handle(Geom_TrimmedCurve) aMeridian = new Geom_TrimmedCurve (aCircle, -PI2, PI2);
+        
+        //Check the meridian
+        Standard_Boolean IsInnerPointFound = Standard_False;
+        Standard_Integer NbSamples = 10;
+        Standard_Real aDelta = M_PI / NbSamples;
+        for (Standard_Integer jj = 1; jj < NbSamples; jj++)
+        {
+          Standard_Real aParam = -PI2 + jj*aDelta;
+          gp_Pnt aPnt = aMeridian->Value (aParam);
+          ElSLib::Parameters (sp, aPnt, aU, aV);
+          gp_Pnt2d aP2d (aU, aV);
+          aStatus = aClassifier.Perform (aP2d);
+          if (aStatus != TopAbs_OUT)
+          {
+            IsInnerPointFound = Standard_True;
+            break;
+          }
+        }
+        if (IsInnerPointFound)
+        {
+          aEmap.Add(anEdge);
+          continue;
+        }
+        
+        gp_Ax3 anAxisOfNewSphere (aCentre, anUp, XDirOfCircle);
+        aNewSurface = new Geom_SphericalSurface (anAxisOfNewSphere, Radius);
+        break;
+      } //for (; itw.More(); itw.Next()) (iteration on outer wire)
+      if (!aNewSurface.IsNull())
+        break;
+    } //for (Standard_Integer ii = 1; ii <= 2; ii++) (two passes)
   }
-  return Standard_False;
+
+  if (aNewSurface.IsNull())
+    return Standard_False;
+
+  theNewSurface = aNewSurface;
+  return Standard_True;
 }
 
 Standard_Boolean BlockFix_SphereSpaceModifier::NewSurface(const TopoDS_Face& F,