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