Salome HOME
a619df6aa9963fc5036233689ee228da49a14011
[modules/geom.git] / src / ShHealOper / ShHealOper_FillHoles.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:      ShHealOper_FillHoles.cxx
24 // Created:   26.04.04 17:35:30
25 // Author:    Galina KULIKOVA
26
27 #include <ShapeFix_Shell.hxx>
28 #include <ShapeFix_Face.hxx>
29 #include <ShHealOper_FillHoles.hxx>
30 #include <ShapeAnalysis_FreeBounds.hxx>
31
32 #include <Basics_OCCTVersion.hxx>
33
34 #include <BRep_Tool.hxx>
35 #include <BRepAdaptor_Curve.hxx>
36 #if OCC_VERSION_LARGE < 0x07070000
37 #include <BRepAdaptor_HCurve.hxx>
38 #endif
39 #include <BRep_Builder.hxx>
40 #include <BRepFill_CurveConstraint.hxx>
41 #include <BRepBuilderAPI_MakeFace.hxx>
42
43 #include <TopAbs_ShapeEnum.hxx>
44 #include <TopExp.hxx>
45 #include <TopExp_Explorer.hxx>
46 #include <TopoDS.hxx>
47 #include <TopoDS_Edge.hxx>
48 #include <TopoDS_Shell.hxx>
49 #include <TopoDS_Compound.hxx>
50 #include <TopoDS_Iterator.hxx>
51 #include <TopLoc_Location.hxx>
52 #include <TopTools_ListOfShape.hxx>
53 #include <TopTools_HSequenceOfShape.hxx>
54 #include <TopTools_IndexedMapOfShape.hxx>
55
56 #include <Geom_Curve.hxx>
57 #include <Geom_BSplineSurface.hxx>
58 #include <GeomPlate_Surface.hxx>
59 #include <GeomPlate_MakeApprox.hxx>
60 #include <GeomPlate_CurveConstraint.hxx>
61 #include <GeomPlate_PlateG0Criterion.hxx>
62 #include <GeomPlate_BuildPlateSurface.hxx>
63
64 #include <TColgp_SequenceOfXY.hxx>
65 #include <TColgp_SequenceOfXYZ.hxx>
66
67 #include <Precision.hxx>
68
69 //=======================================================================
70 //function : ShHealOper_FillHoles()
71 //purpose  : Constructor
72 //=======================================================================
73 ShHealOper_FillHoles::ShHealOper_FillHoles ()
74 {
75   InitParameters();
76 }
77
78 //=======================================================================
79 //function : ShHealOper_FillHoles
80 //purpose  :
81 //=======================================================================
82 ShHealOper_FillHoles::ShHealOper_FillHoles (const TopoDS_Shape& theShape)
83 {
84   Init(theShape);
85   InitParameters();
86 }
87
88 //=======================================================================
89 //function : Init
90 //purpose  :
91 //=======================================================================
92 void ShHealOper_FillHoles::Init(const TopoDS_Shape& theShape)
93 {
94   ShHealOper_Tool::Init(theShape);
95   TopExp::MapShapesAndAncestors( myInitShape, TopAbs_EDGE,TopAbs_SHELL   , myEdgeShells);
96   TopExp::MapShapesAndAncestors ( myInitShape, TopAbs_EDGE,TopAbs_COMPOUND, myEdgeComps );
97
98   TopExp::MapShapesAndAncestors ( myInitShape, TopAbs_EDGE,TopAbs_FACE, myEdgeFaces );
99 }
100
101 //=======================================================================
102 //function : InitParameters
103 //purpose  :
104 //=======================================================================
105 void ShHealOper_FillHoles::InitParameters(Standard_Integer theDegree,
106                                           Standard_Integer theNbPtsOnCur,
107                                           Standard_Integer theNbIter,
108                                           Standard_Real theTol3d,
109                                           Standard_Real theTol2d,
110                                           Standard_Real theTolAng,
111                                           Standard_Real theTolCrv,
112                                           Standard_Integer theMaxDeg,
113                                           Standard_Integer theMaxSeg)
114 {
115   myNbPtsOnCur = theNbPtsOnCur;
116   myNbIter = theNbIter;
117   myDegree =theDegree;
118   myTol2d = theTol2d;
119   myTol3d = theTol3d;
120   myTolAng = theTolAng;
121   myTolCrv = theTolCrv;
122   myMaxDeg = theMaxDeg;
123   myMaxSeg =theMaxSeg;
124 }
125 //=======================================================================
126 //function : Fill
127 //purpose  :
128 //=======================================================================
129 Standard_Boolean ShHealOper_FillHoles::Fill()
130 {
131   ShapeAnalysis_FreeBounds sab(myInitShape);
132   TopoDS_Compound aCompClosed = sab.GetClosedWires();
133   TopoDS_Compound aCompOpen = sab.GetOpenWires();
134   TopTools_SequenceOfShape aFillWires;
135   if(!aCompClosed.IsNull()) {
136     TopoDS_Iterator aIt(aCompClosed);
137
138     for( ; aIt.More(); aIt.Next())
139       aFillWires.Append(aIt.Value());
140   }
141   if(!aCompOpen.IsNull()) {
142     TopoDS_Iterator aIt(aCompOpen);
143     for(  ; aIt.More(); aIt.Next())
144       aFillWires.Append(aIt.Value());
145   }
146
147   TopExp_Explorer aExp(myInitShape,TopAbs_EDGE,TopAbs_FACE);
148
149   for( ; aExp.More(); aExp.Next())
150     aFillWires.Append(aExp.Current());
151
152   return Fill(aFillWires);
153 }
154
155 //=======================================================================
156 //function : Fill
157 //purpose  :
158 //=======================================================================
159 Standard_Boolean ShHealOper_FillHoles::Fill(const TopTools_SequenceOfShape& theFillShapes)
160 {
161   myDone = Standard_False;
162   myErrorStatus = ShHealOper_NotError;
163   if(myInitShape.IsNull()) {
164     myErrorStatus = ShHealOper_InvalidParameters;
165     return myDone;
166   }
167   if(!theFillShapes.Length()) {
168     return myDone;
169   }
170
171   Handle(TopTools_HSequenceOfShape) aSeqWires = new TopTools_HSequenceOfShape;
172   if(!prepareWires(theFillShapes,aSeqWires)) {
173     myErrorStatus = ShHealOper_InvalidParameters;
174     return myDone;
175   }
176
177   myResultShape = myInitShape;
178   Standard_Integer i =1;
179   for( ; i <= aSeqWires->Length(); i++) {
180     TopoDS_Wire aWire = TopoDS::Wire(aSeqWires->Value(i));
181     Handle(TColGeom2d_HArray1OfCurve) aCurves2d;
182     Handle(TColStd_HArray1OfInteger) aOrders;
183     Handle(TColStd_HArray1OfInteger) aSenses;
184     Handle(Geom_Surface) aSurf = buildSurface(aWire,aCurves2d,aOrders,aSenses);
185     if(aSurf.IsNull())
186       myErrorStatus = ShHealOper_ErrorExecution;
187     else
188       myDone = (addFace(aSurf,aWire,aCurves2d,aOrders,aSenses) || myDone);
189   }
190   if(myDone)
191   {
192     myResultShape = myContext->Apply(myResultShape);
193     myStatistics.AddModif( "Face created to fill hole" , aSeqWires->Length() );
194   }
195   return myDone;
196 }
197
198 //=======================================================================
199 //function : isCircle
200 //purpose  :
201 //=======================================================================
202 static Standard_Boolean isCircle(const TopoDS_Edge theEdge)
203 {
204   Standard_Real aFirst, aLast;
205   Handle(Geom_Curve) aC3D = BRep_Tool::Curve(theEdge,aFirst, aLast );
206   if(aC3D.IsNull()) return Standard_False;
207   Standard_Boolean isCirc = (aC3D->Value(aFirst).Distance(aC3D->Value(aLast)) <
208      aC3D->Value(aFirst).Distance(aC3D->Value((aFirst +aLast)/2)));
209   return isCirc;
210 }
211 //=======================================================================
212 //function : prepareWires
213 //purpose  :
214 //=======================================================================
215
216 Standard_Boolean ShHealOper_FillHoles::prepareWires(const TopTools_SequenceOfShape& theFillShapes,
217                                                     Handle(TopTools_HSequenceOfShape)& theSeqWires)
218 {
219   Handle(TopTools_HSequenceOfShape) aSeqEdges = new TopTools_HSequenceOfShape;
220   Standard_Integer i =1;
221   for( ; i <= theFillShapes.Length(); i++) {
222     TopExp_Explorer aExp;
223     for (aExp.Init (theFillShapes.Value(i),TopAbs_WIRE); aExp.More(); aExp.Next()) {
224       TopoDS_Iterator aIt(aExp.Current());
225       Standard_Boolean isAdd = Standard_True;
226       for( ; aIt.More() && isAdd; aIt.Next()) {
227         if(myEdgeFaces.Contains(aIt.Value()))
228           isAdd =  (myEdgeFaces.FindFromKey(aIt.Value()).Extent() <2);
229       }
230       if(isAdd)
231         theSeqWires->Append(aExp.Current());
232     }
233     for (aExp.Init (theFillShapes.Value(i),TopAbs_EDGE, TopAbs_WIRE); aExp.More(); aExp.Next()) {
234       if (!BRep_Tool::Degenerated (TopoDS::Edge (aExp.Current())))
235         if(myEdgeFaces.Contains(aExp.Current()) && myEdgeFaces.FindFromKey(aExp.Current()).Extent() >1)
236           continue;
237       aSeqEdges->Append(aExp.Current()); // to do: mustn't this clause be within if(!BRep_Tool::Degenerated...)?
238     }
239   }
240
241   if(aSeqEdges->Length())
242   {
243     Standard_Real aTol = 0.;
244     Standard_Boolean aShared = Standard_True;
245     Handle(TopTools_HSequenceOfShape) aTmpWires = new TopTools_HSequenceOfShape;
246     ShapeAnalysis_FreeBounds::ConnectEdgesToWires(aSeqEdges, aTol, aShared, aTmpWires);
247     Handle(TopTools_HSequenceOfShape) anWiresClosed = new TopTools_HSequenceOfShape,
248     anWiresOpen   = new TopTools_HSequenceOfShape;
249     ShapeAnalysis_FreeBounds::SplitWires(aTmpWires, aTol, aShared, anWiresClosed, anWiresOpen);
250
251     for (i = 1; i <= anWiresClosed->Length(); i++)
252       theSeqWires->Append (anWiresClosed->Value (i));
253     for (i = 1; i <= anWiresOpen->Length(); i++)
254       theSeqWires->Append (anWiresOpen->Value (i));
255   }
256
257   for( i =1; i <= theSeqWires->Length(); i++) {
258     TopoDS_Wire aWire = TopoDS::Wire(theSeqWires->Value(i));
259
260     TopoDS_Iterator aIt(aWire);
261     Standard_Integer ne =0;
262     TopoDS_Edge ae;
263     for( ; aIt.More(); aIt.Next(), ne++)
264       ae = TopoDS::Edge(aIt.Value());
265     if((ne == 1) && ( !isCircle(ae))) {
266       theSeqWires->Remove(i--);
267       continue;
268     }
269   }
270   return (theSeqWires->Length());
271 }
272 //=======================================================================
273 //function : buildSurface
274 //purpose  :
275 //=======================================================================
276
277 Handle(Geom_Surface) ShHealOper_FillHoles::buildSurface(const TopoDS_Wire& theWire,
278                                                         Handle(TColGeom2d_HArray1OfCurve)& theCurves2d,
279                                                         Handle(TColStd_HArray1OfInteger)& theOrders,
280                                                         Handle(TColStd_HArray1OfInteger)& theSenses)
281 {
282   Handle(Geom_BSplineSurface) aSurf;
283   try {
284     GeomPlate_BuildPlateSurface aBuilder(myDegree, myNbPtsOnCur, myNbIter,
285                                          myTol2d, myTol3d, myTolAng, myTolCrv);
286     TopoDS_Iterator aIter;
287     for(aIter.Initialize (theWire); aIter.More(); aIter.Next()) {
288
289       TopoDS_Edge ae = TopoDS::Edge(aIter.Value());
290       BRepAdaptor_Curve adC(ae);
291 #if OCC_VERSION_LARGE < 0x07070000
292       Handle(BRepAdaptor_HCurve) aHAD = new BRepAdaptor_HCurve(adC);
293 #else
294       Handle(BRepAdaptor_Curve) aHAD = new BRepAdaptor_Curve(adC);
295 #endif
296       // Handle(BRepFill_CurveConstraint) aConst =
297       //     new BRepFill_CurveConstraint (Handle(Adaptor3d_HCurve)::DownCast(aHAD), (Standard_Integer) GeomAbs_C0, myNbPtsOnCur, myTol3d);
298       Handle(GeomPlate_CurveConstraint) aConst =
299         new GeomPlate_CurveConstraint(aHAD, (Standard_Integer) GeomAbs_C0, myNbPtsOnCur, myTol3d);
300       aBuilder.Add (aConst);
301     }
302     aBuilder.Perform();
303     if(!aBuilder.IsDone())
304       return aSurf;
305     Handle(GeomPlate_Surface) aPlSurf = aBuilder.Surface();
306
307     //for filling holes without initial specified surface
308     //the initial surface should be build by GeomPlate itself
309     //following code was taken from BRepFill_Filling::Build
310
311     Standard_Real aDist = aBuilder.G0Error();
312     TColgp_SequenceOfXY S2d;
313     TColgp_SequenceOfXYZ S3d;
314     S2d.Clear();
315     S3d.Clear();
316     aBuilder.Disc2dContour(4,S2d);
317     aBuilder.Disc3dContour(4,0,S3d);
318     Standard_Real amaxTol = Max( myTol3d, 10* aDist);
319     GeomPlate_PlateG0Criterion Criterion( S2d, S3d, amaxTol );
320     GeomPlate_MakeApprox Approx( aPlSurf, Criterion, myTol3d, myMaxSeg, myMaxDeg );
321     aSurf = Approx.Surface();
322     if(aSurf.IsNull())
323       return aSurf;
324
325     theCurves2d = aBuilder.Curves2d();
326     theOrders    = aBuilder.Order();
327     theSenses    = aBuilder.Sense();
328   }
329
330   catch (Standard_Failure&) {
331     aSurf.Nullify();
332     return aSurf;
333   }
334   return aSurf;
335 }
336
337 //=======================================================================
338 //function : addFace
339 //purpose  :
340 //=======================================================================
341
342 Standard_Boolean ShHealOper_FillHoles::addFace(const Handle(Geom_Surface)& theSurf,
343                                                const TopoDS_Wire& theWire,
344                                                const Handle(TColGeom2d_HArray1OfCurve)& theCurves2d,
345                                                const Handle(TColStd_HArray1OfInteger)& theOrders,
346                                                const Handle(TColStd_HArray1OfInteger)& theSenses)
347 {
348   BRepBuilderAPI_MakeFace aMakeFace (theSurf, Precision::Confusion());
349   TopoDS_Face aFace = aMakeFace.Face();
350   aFace.EmptyCopy();
351
352   TopoDS_Wire aWire;
353   BRep_Builder aB;
354   aB.MakeWire(aWire);
355
356   TopTools_IndexedMapOfShape aMapParent;
357   Standard_Integer aInd = 1;
358   Standard_Boolean hasShell = Standard_False;
359   TopoDS_Iterator aIter(theWire);
360   for ( ; aIter.More(); aIter.Next(), aInd++) {
361     TopoDS_Edge anEdge = TopoDS::Edge (aIter.Value());
362     Standard_Real aF, aL;
363     BRep_Tool::Range (anEdge, aF, aL);
364     TopLoc_Location aLoc;
365     aB.UpdateEdge (anEdge, theCurves2d->Value (aInd),aFace, 0.);
366
367     aB.Range (anEdge, aFace, aF, aL);
368
369     // Set orientation of the edge: orientation should be changed
370     // if its orientation does not make sense with curve orientation
371     // recommended by GeomPlate
372     if ((anEdge.Orientation() == TopAbs_FORWARD) ==
373         (theSenses->Value (theOrders->Value (aInd)) == 1)) {
374       anEdge.Reverse();
375     }
376     aB.SameParameter(anEdge,Standard_False);
377     aB.Add (aWire, anEdge);
378     TopoDS_Shape aParent;
379     if(!myEdgeFaces.Contains(anEdge))
380       continue;
381
382     if(myEdgeFaces.FindFromKey(anEdge).Extent() >1)
383       continue;
384
385     if(myEdgeShells.Contains(anEdge)) {
386       if(myEdgeShells.FindFromKey(anEdge).Extent()) {
387        aParent = myEdgeShells.FindFromKey(anEdge).First();
388        hasShell = Standard_True;
389        aMapParent.Add(aParent);
390      }
391     }
392     else if(myEdgeComps.Contains(anEdge)) {
393       if(myEdgeComps.FindFromKey(anEdge).Extent()) {
394         aParent = myEdgeComps.FindFromKey(anEdge).First();
395         aMapParent.Add(aParent);
396       }
397     }
398
399   }
400   aB.Add(aFace,aWire);
401   Handle(ShapeFix_Face) aSff = new ShapeFix_Face(aFace);
402   aSff->SetContext(myContext);
403   aSff->SetPrecision(myTol3d);
404   aSff->Perform();
405   if(aSff->Status(ShapeExtend_FAIL)) {
406     myErrorStatus = ShHealOper_ErrorExecution;
407     return Standard_False;
408   }
409   //theFace = aSff->Face();
410   TopoDS_Shape aResShape = aSff->Result();
411   getResShape(aResShape,aMapParent,hasShell);
412   return Standard_True;
413 }
414
415 //=======================================================================
416 //function : getResShape
417 //purpose  :
418 //=======================================================================
419
420 void ShHealOper_FillHoles::getResShape(const TopoDS_Shape& theAddShape,
421                                        const TopTools_IndexedMapOfShape& aMapParent,
422                                        const Standard_Boolean theHasShell)
423 {
424   BRep_Builder aB;
425
426   if(!aMapParent.Extent()) {
427     TopoDS_Compound aComp;
428     aB.MakeCompound(aComp);
429     TopoDS_Shape aresShape = myContext->Apply(myResultShape);
430     aB.Add(aComp,aresShape);
431     aB.Add(aComp,theAddShape);
432     myResultShape = aComp;
433     return ;
434   }
435   Standard_Boolean anhasShell = theHasShell;
436   TopoDS_Shell aTmpShell;
437   aB.MakeShell(aTmpShell);
438   TopTools_SequenceOfShape aseqShells;
439   if(anhasShell) {
440     aB.Add(aTmpShell,theAddShape);
441     Standard_Integer i =1;
442     for( ; i <= aMapParent.Extent(); i++) {
443       TopoDS_Shape aParShape = myContext->Apply(aMapParent.FindKey(i));
444       if(aParShape.ShapeType() == TopAbs_SHELL) {
445         TopExp_Explorer aexp(aParShape,TopAbs_FACE);
446         for( ; aexp.More(); aexp.Next())
447           aB.Add(aTmpShell,aexp.Current());
448         aseqShells.Append(aParShape);
449       }
450     }
451     anhasShell = aseqShells.Length();
452   }
453   if(anhasShell) {
454     Handle(ShapeFix_Shell) asfs = new ShapeFix_Shell;
455     asfs->FixFaceOrientation(aTmpShell);
456     TopoDS_Shape anshape = asfs->Shape();
457     myContext->Replace(aseqShells.Value(1),anshape);
458     Standard_Integer i =2;
459     for( ; i<= aseqShells.Length(); i++)
460       myContext->Remove(aseqShells.Value(i));
461   }
462   else {
463     TopoDS_Compound aComp;
464     aB.MakeCompound(aComp);
465     TopoDS_Shape oldshape = myContext->Apply(aMapParent.FindKey(1));
466     TopoDS_Iterator aIt(oldshape);
467     for( ; aIt.More(); aIt.Next())
468       aB.Add(aComp,aIt.Value());
469     aB.Add(aComp,theAddShape);
470     myContext->Replace( oldshape,aComp);
471   }
472 }