diff --git a/src/BlockFix/BlockFix_SphereSpaceModifier.cxx b/src/BlockFix/BlockFix_SphereSpaceModifier.cxx index fa8622407..5847d30e5 100644 --- a/src/BlockFix/BlockFix_SphereSpaceModifier.cxx +++ b/src/BlockFix/BlockFix_SphereSpaceModifier.cxx @@ -38,13 +38,17 @@ #include #include #include +#include #include #include +#include +#include +#include -#include -#include - +#include +#include +#include #include #include @@ -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,