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