Salome HOME
99a6e5708c707e2ce442464af4688a25a99e17fa
[modules/geom.git] / src / BlockFix / BlockFix_SphereSpaceModifier.cxx
1 // Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:        BlockFix.cxx
24 // Created:     Tue Dec  7 11:59:05 2004
25 // Author:      Pavel DURANDIN
26
27 #include <BlockFix_SphereSpaceModifier.hxx>
28
29 #include <ShapeAnalysis.hxx>
30
31 #include <ShapeFix_Edge.hxx>
32
33 #include <TopExp.hxx>
34
35 #include <TopLoc_Location.hxx>
36
37 #include <TopoDS.hxx>
38 #include <TopoDS_Edge.hxx>
39 #include <TopoDS_Face.hxx>
40 #include <TopoDS_Vertex.hxx>
41 #include <TopoDS_Iterator.hxx>
42
43 #include <BRep_Tool.hxx>
44 #include <BRep_Builder.hxx>
45 #include <BRepTools.hxx>
46 #include <BRepAdaptor_Curve2d.hxx>
47 #include <BRepTopAdaptor_FClass2d.hxx>
48
49 #include <ElSLib.hxx>
50 #include <Geom_Circle.hxx>
51 #include <Geom_TrimmedCurve.hxx>
52 #include <Geom_SphericalSurface.hxx>
53 #include <Geom_RectangularTrimmedSurface.hxx>
54
55 #include <Geom_Curve.hxx>
56 #include <Geom_Surface.hxx>
57
58 #include <Geom2d_Curve.hxx>
59
60 #include <gp_Pnt.hxx>
61 #include <gp_Sphere.hxx>
62
63 IMPLEMENT_STANDARD_RTTIEXT(BlockFix_SphereSpaceModifier, BRepTools_Modification)
64
65 //=======================================================================
66 //function : BlockFix_SphereSpaceModifier
67 //purpose  :
68 //=======================================================================
69 BlockFix_SphereSpaceModifier::BlockFix_SphereSpaceModifier()
70 {
71   myMapOfFaces.Clear();
72   myMapOfSpheres.Clear();
73 }
74
75 //=======================================================================
76 //function : ~BlockFix_SphereSpaceModifier
77 //purpose  :
78 //=======================================================================
79 BlockFix_SphereSpaceModifier::~BlockFix_SphereSpaceModifier() {}
80
81 //=======================================================================
82 //function : SetTolerance
83 //purpose  :
84 //=======================================================================
85 void BlockFix_SphereSpaceModifier::SetTolerance(const Standard_Real Tol)
86 {
87   myTolerance = Tol;
88 }
89
90 //=======================================================================
91 //function : NewSurface
92 //purpose  :
93 //=======================================================================
94 static Standard_Boolean ModifySurface(const TopoDS_Face&          theFace,
95                                       const Handle(Geom_Surface)& theSurface,
96                                       Handle(Geom_Surface)&       theNewSurface)
97 {
98   TopoDS_Face aFace = theFace;
99   aFace.Orientation (TopAbs_FORWARD);
100
101   Handle(Geom_Surface) aNewSurface;
102   
103   Handle(Geom_Surface) aSurf = theSurface;
104   if (aSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
105     Handle(Geom_RectangularTrimmedSurface) RTS =
106       Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurf);
107     aSurf = RTS->BasisSurface();
108   }
109
110   if (aSurf->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) {
111     Standard_Real Umin, Umax, Vmin, Vmax;
112     ShapeAnalysis::GetFaceUVBounds (aFace, Umin, Umax, Vmin, Vmax);
113     Standard_Real PI2 = M_PI/2.;
114     Handle(Geom_SphericalSurface) aSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf);
115     gp_Sphere sp = aSphere->Sphere();
116     Standard_Real Radius = sp.Radius();
117     gp_Ax3 ax3 = sp.Position();
118     gp_Pnt aCentre = sp.Location();
119     
120     TopoDS_Wire aWire = BRepTools::OuterWire (aFace);
121     BRepTopAdaptor_FClass2d aClassifier (aFace, Precision::PConfusion());
122     TopTools_MapOfShape aEmap;
123     const Standard_Real anOffsetValue = 0.01*M_PI;
124     for (Standard_Integer ii = 1; ii <= 2; ii++)
125     {
126       TopoDS_Iterator itw (aWire);
127       for (; itw.More(); itw.Next())
128       {
129         const TopoDS_Edge& anEdge = TopoDS::Edge (itw.Value());
130         if (aEmap.Contains (anEdge) ||
131             anEdge.Orientation() == TopAbs_INTERNAL ||
132             anEdge.Orientation() == TopAbs_EXTERNAL ||
133             BRep_Tool::Degenerated (anEdge) ||
134             BRepTools::IsReallyClosed (anEdge, aFace))
135           continue;
136         
137         BRepAdaptor_Curve2d aBAcurve2d (anEdge, aFace);
138         GeomAbs_CurveType aType = aBAcurve2d.GetType();
139         if (ii == 1 && aType == GeomAbs_Line) //first pass: consider only curvilinear edges
140           continue;
141         
142         Standard_Real aMidPar = (aBAcurve2d.FirstParameter() + aBAcurve2d.LastParameter())/2;
143         gp_Pnt2d aMidP2d;
144         gp_Vec2d aTangent;
145         aBAcurve2d.D1 (aMidPar, aMidP2d, aTangent);
146         if (anEdge.Orientation() == TopAbs_REVERSED)
147           aTangent.Reverse();
148         
149         aTangent.Normalize();
150         gp_Vec2d aNormal (aTangent.Y(), -aTangent.X());
151         aNormal *= anOffsetValue;
152         gp_Pnt2d anUpperPole = aMidP2d.Translated (aNormal);
153         if (anUpperPole.Y() < -PI2 || anUpperPole.Y() > PI2)
154         {
155           aEmap.Add(anEdge);
156           continue;
157         }
158         if (anUpperPole.X() < 0.)
159           anUpperPole.SetX (anUpperPole.X() + 2.*M_PI);
160         else if (anUpperPole.X() > 2.*M_PI)
161           anUpperPole.SetX (anUpperPole.X() - 2.*M_PI);
162         
163         TopAbs_State aStatus = aClassifier.Perform (anUpperPole);
164         if (aStatus != TopAbs_OUT)
165         {
166           aEmap.Add(anEdge);
167           continue;
168         }
169         
170         gp_Pnt anUpperPole3d = aSphere->Value (anUpperPole.X(), anUpperPole.Y());
171         gp_Vec aVec (aCentre, anUpperPole3d);
172         aVec.Reverse();
173         gp_Pnt aLowerPole3d = aCentre.Translated (aVec);
174         Standard_Real aU, aV;
175         ElSLib::Parameters (sp, aLowerPole3d, aU, aV);
176         gp_Pnt2d aLowerPole (aU, aV);
177         aStatus = aClassifier.Perform (aLowerPole);
178         if (aStatus != TopAbs_OUT)
179         {
180           aEmap.Add(anEdge);
181           continue;
182         }
183         
184         //Build a meridian
185         gp_Vec anUp (aCentre, anUpperPole3d);
186         anUp.Normalize();
187         gp_Pnt aMidPnt = aSphere->Value (aMidP2d.X(), aMidP2d.Y());
188         gp_Vec aMidOnEdge (aCentre, aMidPnt);
189         aMidOnEdge.Normalize();
190         gp_Vec AxisOfCircle = anUp ^ aMidOnEdge;
191         gp_Vec XDirOfCircle = anUp ^ AxisOfCircle;
192         gp_Ax2 anAxis (aCentre, AxisOfCircle, XDirOfCircle);
193         Handle(Geom_Circle) aCircle = new Geom_Circle (anAxis, Radius);
194         Handle(Geom_TrimmedCurve) aMeridian = new Geom_TrimmedCurve (aCircle, -PI2, PI2);
195         
196         //Check the meridian
197         Standard_Boolean IsInnerPointFound = Standard_False;
198         Standard_Integer NbSamples = 10;
199         Standard_Real aDelta = M_PI / NbSamples;
200         for (Standard_Integer jj = 1; jj < NbSamples; jj++)
201         {
202           Standard_Real aParam = -PI2 + jj*aDelta;
203           gp_Pnt aPnt = aMeridian->Value (aParam);
204           ElSLib::Parameters (sp, aPnt, aU, aV);
205           gp_Pnt2d aP2d (aU, aV);
206           aStatus = aClassifier.Perform (aP2d);
207           if (aStatus != TopAbs_OUT)
208           {
209             IsInnerPointFound = Standard_True;
210             break;
211           }
212         }
213         if (IsInnerPointFound)
214         {
215           aEmap.Add(anEdge);
216           continue;
217         }
218         
219         gp_Ax3 anAxisOfNewSphere (aCentre, anUp, XDirOfCircle);
220         aNewSurface = new Geom_SphericalSurface (anAxisOfNewSphere, Radius);
221         break;
222       } //for (; itw.More(); itw.Next()) (iteration on outer wire)
223       if (!aNewSurface.IsNull())
224         break;
225     } //for (Standard_Integer ii = 1; ii <= 2; ii++) (two passes)
226   }
227
228   if (aNewSurface.IsNull())
229     return Standard_False;
230
231   theNewSurface = aNewSurface;
232   return Standard_True;
233 }
234
235 Standard_Boolean BlockFix_SphereSpaceModifier::NewSurface(const TopoDS_Face& F,
236                                                         Handle(Geom_Surface)& S,
237                                                         TopLoc_Location& L,Standard_Real& Tol,
238                                                         Standard_Boolean& RevWires,
239                                                         Standard_Boolean& RevFace)
240 {
241   TopLoc_Location LS;
242   Handle(Geom_Surface) SIni = BRep_Tool::Surface(F, LS);
243
244   //check if pole of the sphere in the parametric space
245   if(ModifySurface(F, SIni, S)) {
246
247     RevWires = Standard_False;
248     RevFace = Standard_False;
249
250     L = LS;
251     Tol = BRep_Tool::Tolerance(F);
252
253     Standard_Integer anIndex = myMapOfSpheres.Add(S);
254     myMapOfFaces.Bind(F,anIndex);
255     return Standard_True;
256   }
257
258   return Standard_False;
259 }
260
261 //=======================================================================
262 //function : NewCurve
263 //purpose  :
264 //=======================================================================
265 Standard_Boolean BlockFix_SphereSpaceModifier::NewCurve(const TopoDS_Edge& /*E*/,Handle(Geom_Curve)& /*C*/,
266                                                         TopLoc_Location& /*L*/,Standard_Real& /*Tol*/)
267 {
268   return Standard_False;
269 }
270
271 //=======================================================================
272 //function : NewPoint
273 //purpose  :
274 //=======================================================================
275 Standard_Boolean BlockFix_SphereSpaceModifier::NewPoint(const TopoDS_Vertex& /*V*/,
276                                                       gp_Pnt& /*P*/,
277                                                       Standard_Real& /*Tol*/)
278 {
279   return Standard_False;
280 }
281
282 //=======================================================================
283 //function : NewCurve2d
284 //purpose  :
285 //=======================================================================
286 Standard_Boolean BlockFix_SphereSpaceModifier::NewCurve2d(const TopoDS_Edge& E,const TopoDS_Face& F,
287                                                         const TopoDS_Edge& /*NewE*/,const TopoDS_Face& /*NewF*/,
288                                                         Handle(Geom2d_Curve)& C,Standard_Real& Tol)
289 {
290   //check if undelying surface of the face was modified
291   if(myMapOfFaces.IsBound(F)) {
292     Standard_Integer anIndex = myMapOfFaces.Find(F);
293
294     Handle(Geom_Surface) aNewSphere = Handle(Geom_Surface)::DownCast(myMapOfSpheres.FindKey(anIndex));
295
296     Standard_Real f,l;
297     TopLoc_Location LC, LS;
298     Handle(Geom_Curve) C3d = BRep_Tool::Curve ( E, LC, f, l );
299     Handle(Geom_Surface) S = BRep_Tool::Surface(F, LS);
300
301     //taking into account the orientation of the seam
302     C = BRep_Tool::CurveOnSurface(E,F,f,l);
303     Tol = BRep_Tool::Tolerance(E);
304
305     BRep_Builder B;
306     TopoDS_Edge TempE;
307     B.MakeEdge(TempE);
308     B.Add(TempE, TopExp::FirstVertex(E));
309     B.Add(TempE, TopExp::LastVertex(E));
310
311     if(!C3d.IsNull())
312       B.UpdateEdge(TempE, Handle(Geom_Curve)::DownCast(C3d->Transformed(LC.Transformation())), Precision::Confusion());
313     B.Range(TempE, f, l);
314
315     Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
316     Handle(Geom_Surface) STemp = Handle(Geom_Surface)::DownCast(aNewSphere->Transformed(LS.Transformation()));
317     TopLoc_Location LTemp;
318     LTemp.Identity();
319
320     Standard_Boolean isClosed = BRep_Tool::IsClosed (E, F);
321     Standard_Real aWorkTol = 2*myTolerance+Tol;
322     sfe->FixAddPCurve(TempE, STemp, LTemp, isClosed, Max(Precision::Confusion(), aWorkTol));
323     sfe->FixSameParameter(TempE);
324
325     //keep the orientation of original edge
326     TempE.Orientation(E.Orientation());
327     C = BRep_Tool::CurveOnSurface(TempE, STemp, LTemp, f, l);
328
329     // shifting seam of sphere
330     if(isClosed  && !C.IsNull()) {
331       Standard_Real f2,l2;
332       Handle(Geom2d_Curve) c22 =
333         BRep_Tool::CurveOnSurface(TopoDS::Edge(TempE.Reversed()),STemp, LTemp,f2,l2);
334       Standard_Real dPreci = Precision::PConfusion()*Precision::PConfusion();
335       if((C->Value(f).SquareDistance(c22->Value(f2)) < dPreci)
336          ||(C->Value(l).SquareDistance(c22->Value(l2)) < dPreci)) {
337         gp_Vec2d shift(S->UPeriod(),0.);
338         C->Translate(shift);
339       }
340     }
341     //sphere was modified
342     return Standard_True;
343   }
344
345   return Standard_False;
346 }
347
348 //=======================================================================
349 //function : NewParameter
350 //purpose  :
351 //=======================================================================
352 Standard_Boolean BlockFix_SphereSpaceModifier::NewParameter(const TopoDS_Vertex& /*V*/,const TopoDS_Edge& /*E*/,
353                                                             Standard_Real& /*P*/,Standard_Real& /*Tol*/)
354 {
355   return Standard_False;
356 }
357
358 //=======================================================================
359 //function : Continuity
360 //purpose  :
361 //=======================================================================
362 GeomAbs_Shape BlockFix_SphereSpaceModifier::Continuity(const TopoDS_Edge& E,const TopoDS_Face& F1,
363                                                      const TopoDS_Face& F2,const TopoDS_Edge& /*NewE*/,
364                                                      const TopoDS_Face& /*NewF1*/,const TopoDS_Face& /*NewF2*/)
365 {
366   return BRep_Tool::Continuity(E,F1,F2);
367 }