Salome HOME
[bos #36177] [FORUM] - Remove extra-edge on hemisphere
[modules/geom.git] / src / BlockFix / BlockFix.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, 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.hxx>
28
29 #include <BlockFix_SphereSpaceModifier.hxx>
30 #include <BlockFix_PeriodicSurfaceModifier.hxx>
31
32 #include <TopExp.hxx>
33 #include <TopExp_Explorer.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_Wire.hxx>
41 #include <TopoDS_Shape.hxx>
42 #include <TopoDS_Solid.hxx>
43 #include <TopoDS_Vertex.hxx>
44
45 #include <TopTools_ListOfShape.hxx>
46 #include <TopTools_ListIteratorOfListOfShape.hxx>
47 #include <TopTools_MapOfShape.hxx>
48 #include <TopTools_DataMapOfShapeShape.hxx>
49 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
50
51 #include <BRep_Tool.hxx>
52 #include <BRep_Builder.hxx>
53
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBndLib.hxx>
56
57 #include <BRepTools.hxx>
58 #include <BRepTools_Modifier.hxx>
59 #include <BRepTools_Substitution.hxx>
60
61 #include <BRepOffsetAPI_MakeFilling.hxx>
62
63 #include <ShapeFix.hxx>
64 #include <ShapeFix_Edge.hxx>
65 #include <ShapeFix_Face.hxx>
66
67 #include <ShapeAnalysis.hxx>
68 #include <ShapeAnalysis_Edge.hxx>
69 #include <ShapeAnalysis_Curve.hxx>
70 #include <ShapeAnalysis_Surface.hxx>
71
72 #include <ShapeCustom.hxx>
73
74 #include <ShapeBuild_Edge.hxx>
75 #include <ShapeBuild_ReShape.hxx>
76
77 #include <ShapeFix_Wire.hxx>
78
79 #include <Geom_Surface.hxx>
80 #include <Geom_CylindricalSurface.hxx>
81 #include <Geom_ConicalSurface.hxx>
82 #include <Geom_SphericalSurface.hxx>
83 #include <Geom_ToroidalSurface.hxx>
84
85 #include <Geom2d_Curve.hxx>
86
87 #include <TColgp_SequenceOfPnt2d.hxx>
88
89 #include <Basics_OCCTVersion.hxx>
90
91 static Standard_Real ComputeMaxTolOfFace(const TopoDS_Face& theFace)
92 {
93   Standard_Real MaxTol = BRep_Tool::Tolerance(theFace);
94
95   TopTools_IndexedMapOfShape aMap;
96   TopExp::MapShapes(theFace, TopAbs_EDGE, aMap);
97   for (Standard_Integer i = 1; i <= aMap.Extent(); i++)
98   {
99     const TopoDS_Edge& anEdge = TopoDS::Edge(aMap(i));
100     Standard_Real aTol = BRep_Tool::Tolerance(anEdge);
101     if (aTol > MaxTol)
102       MaxTol = aTol;
103   }
104
105   aMap.Clear();
106   TopExp::MapShapes(theFace, TopAbs_VERTEX, aMap);
107   for (Standard_Integer i = 1; i <= aMap.Extent(); i++)
108   {
109     const TopoDS_Vertex& aVertex = TopoDS::Vertex(aMap(i));
110     Standard_Real aTol = BRep_Tool::Tolerance(aVertex);
111     if (aTol > MaxTol)
112       MaxTol = aTol;
113   }
114
115   return MaxTol;
116 }
117
118 //=======================================================================
119 //function : FixResult
120 //purpose  : auxiliary
121 //=======================================================================
122 static void FixResult(const TopoDS_Shape& result,
123                       Handle(ShapeBuild_ReShape)& Context,
124                       const Standard_Real Tol)
125 {
126   for (TopExp_Explorer ex_f(result,TopAbs_FACE); ex_f.More(); ex_f.Next()) {
127     TopoDS_Shape aShape = Context->Apply(ex_f.Current().Oriented(TopAbs_FORWARD));
128     // face could not be dropped or split on this step
129     TopoDS_Face aFace = TopoDS::Face(aShape);
130     TopLoc_Location L;
131     Handle(Geom_Surface) Surf = BRep_Tool::Surface(aFace,L);
132
133     if( Surf->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ||
134         Surf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ) {
135
136       Standard_Integer nbWires = 0;
137       for (TopExp_Explorer ex_w(aFace,TopAbs_WIRE); ex_w.More(); ex_w.Next()) {
138         nbWires++;
139         Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(TopoDS::Wire(ex_w.Current()),
140                                                       aFace,
141                                                       Precision::Confusion());
142         sfw->FixReorder();
143         if(sfw->StatusReorder ( ShapeExtend_FAIL ))
144           continue;
145
146         sfw->SetPrecision(2.*Tol);
147         sfw->FixShifted();
148
149         Standard_Boolean isDone = sfw->LastFixStatus ( ShapeExtend_DONE );
150         isDone |= sfw->FixDegenerated();
151
152         // remove degenerated edges from not degenerated points
153         ShapeAnalysis_Edge sae;
154         Handle(ShapeExtend_WireData) sewd = sfw->WireData();
155         Standard_Integer i;
156         for( i = 1; i<=sewd->NbEdges();i++) {
157           TopoDS_Edge E = sewd->Edge(i);
158           if(BRep_Tool::Degenerated(E)&&!sae.HasPCurve(E,aFace)) {
159             sewd->Remove(i);
160             isDone = Standard_True;
161             i--;
162           }
163         }
164
165         //isDone |= sfw->FixLacking(); // commented by skl 22.03.2005 (PAL8395)
166
167         // remove neighbour seam edges
168         if(isDone) {
169           for( i = 1; i<sewd->NbEdges();i++) {
170             if(sewd->IsSeam(i) && sewd->IsSeam(i+1)) {
171               isDone = Standard_True;
172               sewd->Remove(i);
173               sewd->Remove(i);
174               i--;
175             }
176           }
177           if(sewd->IsSeam(1) && sewd->IsSeam(sewd->NbEdges())) {
178             sewd->Remove(1);
179             sewd->Remove(sewd->NbEdges());
180           }
181         }
182
183         if(isDone) {
184           TopoDS_Wire ResWire = sfw->Wire();
185           Context->Replace(ex_w.Current(), ResWire);
186         };
187       }
188       // Implement fix orientation in case of several wires
189       if(nbWires > 1) {
190         TopoDS_Face aFixedFace = TopoDS::Face(Context->Apply(aFace));
191         Handle(ShapeFix_Face) sff = new ShapeFix_Face(aFixedFace);
192         if(sff->FixOrientation())
193           Context->Replace(aFixedFace,sff->Face());
194       }
195     }
196   }
197 }
198
199 //=======================================================================
200 //function : RotateSphereSpace
201 //purpose  :
202 //=======================================================================
203 TopoDS_Shape BlockFix::RotateSphereSpace (const TopoDS_Shape& S,
204                                           const Standard_Real Tol,
205                                           const Standard_Boolean theTrySmallRotation)
206 {
207   // Create a modification description
208   Handle(BlockFix_SphereSpaceModifier) SR = new BlockFix_SphereSpaceModifier;
209   SR->SetTolerance(Tol);
210   SR->SetTrySmallRotation(theTrySmallRotation);
211
212   TopTools_DataMapOfShapeShape context;
213   BRepTools_Modifier MD;
214   TopoDS_Shape result = ShapeCustom::ApplyModifier ( S, SR, context, MD );
215
216   Handle(ShapeBuild_ReShape) RS = new ShapeBuild_ReShape;
217   FixResult(result,RS,Tol);
218   result = RS->Apply(result);
219
220   ShapeFix_Edge sfe;
221   for (TopExp_Explorer exp (result, TopAbs_EDGE); exp.More(); exp.Next()) {
222     TopoDS_Edge E = TopoDS::Edge(exp.Current());
223     sfe.FixVertexTolerance (E);
224   }
225
226   ShapeFix::SameParameter(result, Standard_False);
227   return result;
228 }
229
230 //=======================================================================
231 //function : RefillProblemFaces
232 //purpose  :
233 //=======================================================================
234 TopoDS_Shape BlockFix::RefillProblemFaces (const TopoDS_Shape& aShape)
235 {
236   Standard_Integer NbSamples = 10;
237
238 #if OCC_VERSION_LARGE > 0x07040000
239   TopTools_IndexedDataMapOfShapeListOfShape VFmap;
240   TopExp::MapShapesAndUniqueAncestors(aShape, TopAbs_VERTEX, TopAbs_FACE, VFmap);
241 #endif
242
243   TopTools_ListOfShape theFaces;
244
245   TopExp_Explorer Explo(aShape, TopAbs_FACE);
246   for (; Explo.More(); Explo.Next())
247   {
248     TopoDS_Face aFace = TopoDS::Face(Explo.Current());
249     BRepAdaptor_Surface BAsurf(aFace);
250     GeomAbs_SurfaceType SurfType = BAsurf.GetType();
251     if (SurfType >= GeomAbs_BezierSurface)
252     {
253       TopExp_Explorer fexp(aFace, TopAbs_EDGE);
254       for (; fexp.More(); fexp.Next())
255       {
256         const TopoDS_Edge& anEdge = TopoDS::Edge(fexp.Current());
257         if (BRep_Tool::Degenerated(anEdge))
258         {
259           TopoDS_Vertex V1, V2;
260           TopExp::Vertices(anEdge, V1, V2);
261           if (V1.IsSame(V2))
262           {
263             gp_Pnt aPnt = BRep_Tool::Pnt(V1);
264             Standard_Real TolV = BRep_Tool::Tolerance(V1);
265             Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
266             Handle(ShapeAnalysis_Surface) Analyser = new ShapeAnalysis_Surface(aSurf);
267             if (Analyser->IsDegenerated(aPnt, TolV))
268             {
269               theFaces.Append(aFace);
270               break;
271             }
272           }
273         }
274       }
275     }
276   }
277
278   //Now all problem faces are collected in the list "theFaces"
279   BRepTools_Substitution aSubst;
280   TopTools_ListIteratorOfListOfShape itl(theFaces);
281   for (; itl.More(); itl.Next())
282   {
283     TopoDS_Face aFace = TopoDS::Face(itl.Value());
284     aFace.Orientation(TopAbs_FORWARD);
285
286     //Compute proper tolerance
287     Standard_Real MaxTolOfFace = ComputeMaxTolOfFace(aFace);
288 #if OCC_VERSION_LARGE > 0x07040000
289     Bnd_Box aBndBox;
290     BRepBndLib::Add(aFace, aBndBox);
291     Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
292     aBndBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
293     Standard_Real LinSize = Min(Xmax - Xmin, Min(Ymax - Ymin, Zmax - Zmin));
294     Standard_Real LinTol = Max(0.001*LinSize, 1.5*MaxTolOfFace);
295 #endif
296     
297     BRepAdaptor_Surface BAsurf(aFace, Standard_False);
298     BRepOffsetAPI_MakeFilling Filler(3, 10);
299     TopExp_Explorer Explo(aFace, TopAbs_EDGE);
300     for (; Explo.More(); Explo.Next())
301     {
302       const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current());
303       if (BRep_Tool::Degenerated(anEdge) ||
304           BRepTools::IsReallyClosed(anEdge, aFace))
305         continue;
306       
307       Filler.Add(anEdge, GeomAbs_C0);
308       //Filler.Add(anEdge, aFace, GeomAbs_G1);
309     }
310     Standard_Real Umin, Umax, Vmin, Vmax;
311     BRepTools::UVBounds(aFace, Umin, Umax, Vmin, Vmax);
312     Standard_Real DeltaU = (Umax - Umin)/NbSamples,
313       DeltaV = (Vmax - Vmin)/NbSamples;
314     for (Standard_Integer i = 1; i < NbSamples; i++)
315       for (Standard_Integer j = 1; j < NbSamples; j++) {
316         Filler.Add(Umin + i*DeltaU, Vmin + j*DeltaV, aFace, GeomAbs_G1);
317       }
318
319     Filler.Build();
320     if (Filler.IsDone())
321     {
322       TopoDS_Face aNewFace = TopoDS::Face(Filler.Shape());
323       aNewFace.Orientation(TopAbs_FORWARD);
324       Handle(Geom_Surface) aNewSurf = BRep_Tool::Surface(aNewFace);
325       GeomAdaptor_Surface GAnewsurf(aNewSurf);
326       Extrema_ExtPS Projector;
327       Projector.Initialize(GAnewsurf, GAnewsurf.FirstUParameter(), GAnewsurf.LastUParameter(),
328                            GAnewsurf.FirstVParameter(), GAnewsurf.LastVParameter(),
329                            Precision::Confusion(), Precision::Confusion());
330       Standard_Real MaxSqDist = 0.;
331       for (Standard_Integer i = 0; i < NbSamples; i++)
332         for (Standard_Integer j = 0; j < NbSamples; j++)
333         {
334           gp_Pnt aPoint = BAsurf.Value(Umin + DeltaU/2 + i*DeltaU,
335                                        Vmin + DeltaV/2 + j*DeltaV);
336           Projector.Perform(aPoint);
337           if (Projector.IsDone())
338           {
339             Standard_Real LocalMinSqDist = RealLast();
340             for (Standard_Integer ind = 1; ind <= Projector.NbExt(); ind++)
341             {
342               Standard_Real aSqDist = Projector.SquareDistance(ind);
343               if (aSqDist < LocalMinSqDist)
344                 LocalMinSqDist = aSqDist;
345             }
346             if (!Precision::IsInfinite(LocalMinSqDist) &&
347                 LocalMinSqDist > MaxSqDist)
348               MaxSqDist = LocalMinSqDist;
349           }
350         }
351       Standard_Real MaxDist = Sqrt(MaxSqDist);
352 #if OCC_VERSION_LARGE > 0x07040000
353       if (MaxDist < LinTol)
354 #else
355       if (MaxDist < Max(1.e-4, 1.5*MaxTolOfFace))
356 #endif
357       {
358         TopTools_IndexedMapOfShape Emap;
359 #if OCC_VERSION_LARGE > 0x07040000
360         TopTools_MapOfShape Vmap;
361 #endif
362         TopExp::MapShapes(aFace, TopAbs_EDGE, Emap);
363         for (Standard_Integer i = 1; i <= Emap.Extent(); i++)
364         {
365           TopoDS_Edge anEdge = TopoDS::Edge(Emap(i));
366           anEdge.Orientation(TopAbs_FORWARD);
367 #if OCC_VERSION_LARGE > 0x07040000
368           TopoDS_Vertex V1, V2;
369           TopExp::Vertices(anEdge, V1, V2);
370           TopTools_ListOfShape ListV1, ListV2;
371 #endif
372           TopTools_ListOfShape Ledge;
373           if (!BRep_Tool::Degenerated(anEdge) &&
374               !BRepTools::IsReallyClosed(anEdge, aFace))
375           {
376             const TopTools_ListOfShape& Ledges = Filler.Generated(anEdge);
377             if (!Ledges.IsEmpty()) {
378               TopoDS_Edge NewEdge = TopoDS::Edge(Ledges.First());
379               Ledge.Append(NewEdge.Oriented(TopAbs_FORWARD));
380             }
381
382 #if OCC_VERSION_LARGE > 0x07040000
383             TopoDS_Vertex NewV1 = TopoDS::Vertex(Filler.Generated(V1).First());
384             ListV1.Append(NewV1.Oriented(TopAbs_FORWARD));
385
386             if (!V1.IsSame(V2)) {
387               TopoDS_Vertex NewV2 = TopoDS::Vertex(Filler.Generated(V2).First());
388               ListV2.Append(NewV2.Oriented(TopAbs_FORWARD));
389             }
390 #endif
391           }
392           aSubst.Substitute(anEdge, Ledge);
393 #if OCC_VERSION_LARGE > 0x07040000
394           if (!Vmap.Contains(V1) &&
395               (!ListV1.IsEmpty() || VFmap.FindFromKey(V1).Extent() == 1))
396           {
397             aSubst.Substitute(V1, ListV1);
398             Vmap.Add(V1);
399           }
400           if (!Vmap.Contains(V2) &&
401               (!ListV2.IsEmpty() || VFmap.FindFromKey(V2).Extent() == 1))
402           {
403             aSubst.Substitute(V2.Oriented(TopAbs_FORWARD), ListV2);
404             Vmap.Add(V2);
405           }
406 #endif
407         }
408         TopTools_ListOfShape Lface;
409         BRepAdaptor_Surface NewBAsurf(aNewFace);
410         gp_Pnt MidPnt;
411         gp_Vec D1U, D1V, Normal, NewNormal;
412         Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
413         aSurf->D1((Umin+Umax)*0.5, (Vmin+Vmax)*0.5, MidPnt, D1U, D1V);
414         Normal = D1U ^ D1V;
415         NewBAsurf.D1((NewBAsurf.FirstUParameter() + NewBAsurf.LastUParameter())*0.5,
416                      (NewBAsurf.FirstVParameter() + NewBAsurf.LastVParameter())*0.5,
417                      MidPnt, D1U, D1V);
418         NewNormal = D1U ^ D1V;
419         if (Normal * NewNormal < 0.)
420           aNewFace.Reverse();
421         Lface.Append(aNewFace);
422         aSubst.Substitute(aFace, Lface);
423       }
424     }
425   }
426   aSubst.Build(aShape);
427
428   TopoDS_Shape Result = aShape;
429   if (aSubst.IsCopied(aShape))
430     Result = aSubst.Copy(aShape).First();
431
432   BRepTools::RemoveUnusedPCurves(Result);
433
434   return Result;
435 }
436
437 //=======================================================================
438 //function : FixRanges
439 //purpose  :
440 //=======================================================================
441 TopoDS_Shape BlockFix::FixRanges (const TopoDS_Shape& S,
442                                   const Standard_Real Tol)
443 {
444   // Create a modification description
445   Handle(BlockFix_PeriodicSurfaceModifier) SR = new BlockFix_PeriodicSurfaceModifier;
446   SR->SetTolerance(Tol);
447
448   TopTools_DataMapOfShapeShape context;
449   BRepTools_Modifier MD;
450   TopoDS_Shape result = ShapeCustom::ApplyModifier ( S, SR, context,MD );
451
452   Handle(ShapeBuild_ReShape) RS = new ShapeBuild_ReShape;
453   FixResult(result,RS,Tol);
454   result = RS->Apply(result);
455
456   ShapeFix_Edge sfe;
457   for(TopExp_Explorer exp(result,TopAbs_EDGE); exp.More(); exp.Next()) {
458     TopoDS_Edge E = TopoDS::Edge(exp.Current());
459     sfe.FixVertexTolerance (E);
460   }
461
462   ShapeFix::SameParameter(result,Standard_False);
463
464   return result;
465 }