Salome HOME
Merge with version on tag OCC-V2_1_0d
[modules/geom.git] / src / ShHealOper / ShHealOper_RemoveFace.cxx
1 // File:      ShHealOper_RemoveFace.cxx
2 // Created:   16.04.04 12:12:38
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 #include <ShHealOper_RemoveFace.hxx>
24 #include <BRepTools_ReShape.hxx>
25 #include <TopoDS_Shape.hxx>
26 #include <TopAbs_ShapeEnum.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS_Compound.hxx>
29 #include <TopoDS_Solid.hxx>
30 #include <TopoDS_Shell.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <BRep_Builder.hxx>
33 #include <TopoDS_Iterator.hxx>
34 #include <TopExp.hxx>
35 #include <TopTools_ListOfShape.hxx>
36 #include <BRep_Tool.hxx>
37 #include <Geom_Surface.hxx>
38 #include <TopoDS_Edge.hxx>
39 #include <ShapeBuild_Edge.hxx>
40 #include <ShapeFix_Shell.hxx>
41 #include <ShapeFix_Solid.hxx>
42 #include <TopTools_SequenceOfShape.hxx>
43 #include <TopoDS.hxx>
44 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
45 #include <TopTools_ListIteratorOfListOfShape.hxx>
46
47
48 //=======================================================================
49 //function : ShHealOper_RemoveFace()
50 //purpose  : Constructor
51 //=======================================================================
52 ShHealOper_RemoveFace::ShHealOper_RemoveFace () :
53        ShHealOper_Tool()
54 {
55 }
56 //=======================================================================
57 //function : ShHealOper_RemoveFace
58 //purpose  : 
59 //=======================================================================
60
61 ShHealOper_RemoveFace::ShHealOper_RemoveFace ( const TopoDS_Shape& theShape ) 
62        //ShHealOper_Tool(theShape)
63 {
64   Init(theShape);
65 }
66 //=======================================================================
67 //function : Init
68 //purpose  : 
69 //=======================================================================
70
71 void ShHealOper_RemoveFace::Init(const TopoDS_Shape& theShape)
72 {
73   //myDone = Standard_False;
74   //myInitShape = theShape;
75   //myContext->Apply(myInitShape);
76   ShHealOper_Tool::Init(theShape);
77   myMapEdgesFace.Clear();
78   TopExp::MapShapesAndAncestors(theShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgesFace);
79 }
80 //=======================================================================
81 //function : Perform
82 //purpose  : remove all faces from initial shape
83 //=======================================================================
84
85 Standard_Boolean ShHealOper_RemoveFace::Perform()
86 {
87   myDone = Standard_False;
88   myErrorStatus = ShHealOper_NotError;
89   if(myInitShape.IsNull()) {
90     myErrorStatus = ShHealOper_InvalidParameters;
91     return myDone;
92   }
93   TopExp_Explorer aExp(myInitShape,TopAbs_FACE);
94   for( ; aExp.More(); aExp.Next()) {
95     removePCurve(TopoDS::Face(aExp.Current()));
96     myContext->Remove(aExp.Current());
97     myDone = Standard_True;
98   }
99   if(myDone) {
100     TopoDS_Shape aNewShape = myContext->Apply(myInitShape);
101     isReplace(aNewShape,myResultShape);
102     myContext->Replace(aNewShape,myResultShape);
103   }
104   return myDone;
105 }
106 //=======================================================================
107 //function : Perform
108 //purpose  : remove faces specified by sequence of faces from initial shape.
109 //=======================================================================
110
111 Standard_Boolean ShHealOper_RemoveFace::Perform(const TopTools_SequenceOfShape& theRemoveFaces)
112 {
113   myDone = Standard_False;
114   myErrorStatus = ShHealOper_NotError;
115   if(myInitShape.IsNull()) {
116     myErrorStatus = ShHealOper_InvalidParameters;
117     return myDone;
118   }
119   if(theRemoveFaces.IsEmpty())
120     return Standard_False;
121   myMapFaces.Clear();
122   
123   Standard_Integer i=1; 
124   for( ; i <= theRemoveFaces.Length(); i++)
125     myMapFaces.Add(theRemoveFaces.Value(i));
126   
127   myDone = removeFaces(myInitShape,myResultShape);
128   return myDone;
129 }
130
131 //=======================================================================
132 //function : removeFaces
133 //purpose  : 
134 //=======================================================================
135
136 Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Shape& theShape,
137                                                     TopoDS_Shape& theNewShape)
138 {
139   Standard_Boolean isDone = Standard_False;
140   
141   TopAbs_ShapeEnum aType = theShape.ShapeType();
142   theNewShape = theShape;
143   if(!myMapFaces.Extent())
144     return isDone;
145   if( aType == TopAbs_WIRE || aType == TopAbs_EDGE || aType == TopAbs_VERTEX)
146       return isDone;
147   if(aType == TopAbs_FACE && myMapFaces.Contains(theShape)) {
148     removePCurve(TopoDS::Face(theShape));
149     
150     myContext->Remove(theShape);
151     myMapFaces.Remove(theShape);
152     //theNewShape = TopoDS_Shape();
153     theNewShape.Nullify();
154     isDone = Standard_True;
155   }
156   else if(aType == TopAbs_SHELL) {
157     isDone = removeFaces(TopoDS::Shell(theShape),theNewShape);
158     return isDone;
159   }
160   else if(aType == TopAbs_SOLID) {
161     isDone = removeFaces(TopoDS::Solid(theShape),theNewShape);
162     myContext->Replace(theShape,theNewShape);
163   }
164   else if(aType == TopAbs_COMPSOLID) {
165
166     //in the case of compsolid method for removing faces for solid
167     //will be used.
168
169     TopExp_Explorer aExpShell(theShape,TopAbs_SHELL);
170     TopoDS_Solid aSol;
171     BRep_Builder aB;
172     aB.MakeSolid(aSol);
173     for( ; aExpShell.More(); aExpShell.Next()) {
174       aB.Add(aSol,aExpShell.Current());
175     }
176     TopoDS_Shape aNewShape;
177     isDone =  removeFaces(aSol,aNewShape);
178     if(isDone)
179        myContext->Replace(theShape,theNewShape);
180     
181   }
182   else if(aType == TopAbs_COMPOUND) {
183     //in the case of compounf faces will be removed from each part of compound separately
184
185     TopoDS_Compound aComp;
186     TopoDS_Iterator aItShape(theShape,Standard_False);
187     BRep_Builder aB;
188     aB.MakeCompound(aComp);
189     Standard_Integer nbs =0;
190     for( ; aItShape.More() ; aItShape.Next()) {
191
192       TopoDS_Shape aNShape;
193       if( removeFaces(aItShape.Value(),aNShape)) {
194         isDone = Standard_True;
195         myContext->Replace(aItShape.Value(),aNShape);
196       }
197       if(!aNShape.IsNull()) {
198         aB.Add(aComp,aNShape);
199         nbs++;
200       }
201     }
202     if(isDone) {
203       if(nbs) 
204         theNewShape = aComp;
205       else
206         theNewShape =TopoDS_Shape();
207       myContext->Replace(theShape,theNewShape);
208     }
209    
210   }
211   return isDone;
212 }
213 //=======================================================================
214 //function : removeFaces
215 //purpose  : function for removing faces from solid
216 //=======================================================================
217
218 Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Solid& theShape,
219                                                     TopoDS_Shape& theNewShape)
220 {
221   Standard_Boolean isDone = Standard_False;
222   TopoDS_Solid aSol;
223   BRep_Builder aB;
224   aB.MakeSolid(aSol);
225   TopoDS_Compound aComp;
226   aB.MakeCompound(aComp);
227   Standard_Boolean isAddSol = Standard_False, isAddComp = Standard_False;
228
229   //firslty faces will be deleted from each shell.
230   TopoDS_Iterator aItSol(theShape,Standard_False);
231   for( ; aItSol.More(); aItSol.Next()) {
232     TopoDS_Shape aSh = aItSol.Value();
233     TopoDS_Shape aNewShape;
234     if(removeFaces(aSh,aNewShape)) 
235       isDone = Standard_True;
236     
237     if(aNewShape.IsNull())
238       continue;
239     else if(aNewShape.ShapeType() == TopAbs_SHELL ) {
240       aB.Add(aSol,aNewShape);
241       isAddSol = Standard_True;
242     }
243     else {
244       aB.Add(aComp,aNewShape);
245       isAddComp = Standard_True;
246     }
247     
248   }
249   if(isDone) {
250     //for getting correct solids class ShapeFix_Solid will be used.
251     if(isAddSol) {
252       Handle(ShapeFix_Solid) aSfSol = new ShapeFix_Solid(aSol);
253       aSfSol->FixShellMode()= Standard_False;
254       aSfSol->Perform();
255       TopoDS_Shape aresSol = aSfSol->Shape();
256       if(!isAddComp) 
257         theNewShape = aresSol;
258       else 
259         aB.Add(aComp,aresSol);
260     }
261     else if(isAddComp)
262         theNewShape = aComp;
263     else
264       theNewShape.Nullify();
265   }
266   else
267     theNewShape = theShape; 
268   return isDone;
269 }
270 //=======================================================================
271 //function : IsManifold
272 //purpose  : function for definition manifold shell
273 //=======================================================================
274 Standard_Boolean ShHealOper_RemoveFace::isManifold(const TopoDS_Shell& aShell)
275 {
276   Standard_Boolean IsManifold = Standard_True;
277   TopExp_Explorer aExp(aShell,TopAbs_EDGE);
278   for( ; aExp.More() && IsManifold; aExp.Next()) {
279     const TopTools_ListOfShape& als = myMapEdgesFace.FindFromKey(aExp.Current());
280     IsManifold = (als.Extent() <=2 ); 
281   }
282   return IsManifold;
283 }
284
285 //=======================================================================
286 //function : getResultShell
287 //purpose  : function for avoiding empty shall or shell containing one face.
288 //=======================================================================
289 static TopoDS_Shape getResultShell(const TopoDS_Shape& theNewShell)
290 {
291   TopoDS_Shape rs;
292   Standard_Integer NbFacesShell =0;
293   TopoDS_Shape aF;
294   TopoDS_Iterator aI(theNewShell,Standard_False);
295   for(; aI.More(); aI.Next(),NbFacesShell++)
296     aF = aI.Value();
297   if(NbFacesShell >1)
298     rs = theNewShell;
299   else if(!aF.IsNull())
300     rs = aF;
301   return rs;
302 }
303
304 //=======================================================================
305 //function : removeFaces
306 //purpose  : function for removing faces from shell
307 //=======================================================================
308
309 Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Shell& theShell,
310                                                     TopoDS_Shape& theNewShape)
311 {
312   
313   Standard_Boolean aIsRemove = Standard_False;
314   //TopoDS_Shape aShape = myReShape->Apply(theShape);
315   //removing faces from shell.
316   TopoDS_Iterator aIterFaces(theShell,Standard_False);
317   for(; aIterFaces.More() && myMapFaces.Extent(); aIterFaces.Next()) {
318
319     if(!myMapFaces.Contains(aIterFaces.Value()))
320       continue;
321     TopoDS_Face aFace = TopoDS::Face( aIterFaces.Value());
322     removePCurve(aFace);
323     aIsRemove  = Standard_True;
324     myContext->Remove(aFace);
325     myMapFaces.Remove(aFace);
326   }
327   if(aIsRemove) {
328     TopoDS_Shape aNewShape = myContext->Apply(theShell);
329     //avoiding empty shell and shell containing one face.
330     TopoDS_Shape aresShape = getResultShell(aNewShape);
331     if(aresShape.IsNull()) {
332       myContext->Remove(aNewShape);
333       theNewShape.Nullify();
334     }
335     else if(aresShape.ShapeType() == TopAbs_FACE) {
336       myContext->Replace(aNewShape,aresShape);
337       theNewShape = aresShape;
338     }
339     else if(aresShape.ShapeType() == TopAbs_SHELL) {
340       //obtaining correct shell or compound with help class ShapeFix_Shell.
341       Standard_Boolean isManifShell = isManifold(theShell);
342       Handle(ShapeFix_Shell) aFixShell = new ShapeFix_Shell;
343       aFixShell->FixFaceOrientation(TopoDS::Shell(aresShape),Standard_True,!isManifShell);
344       TopoDS_Shape aFixShape = aFixShell->Shape();
345       TopoDS_Shape areplShape;
346       isReplace(aFixShape,areplShape);
347       myContext->Replace(aNewShape,areplShape);
348       theNewShape = areplShape;
349     }
350   }
351   else theNewShape = theShell;
352   return aIsRemove;
353 }
354 //=======================================================================
355 //function : isReplace
356 //purpose  : method to avoiding empty compounds and shells.
357 //=======================================================================
358
359 Standard_Boolean ShHealOper_RemoveFace::isReplace(const TopoDS_Shape& theShape, 
360                                                   TopoDS_Shape& theNewShape)
361 {
362   
363   Standard_Boolean isChange = Standard_False;
364   TopTools_SequenceOfShape aSeqShapes;
365   if(theShape.ShapeType() == TopAbs_COMPOUND || theShape.ShapeType() == TopAbs_COMPSOLID ||
366      theShape.ShapeType() == TopAbs_SOLID) {
367     TopoDS_Iterator aEs(theShape);
368     for( ; aEs.More(); aEs.Next()) {
369       TopoDS_Shape aNewShell = aEs.Value();
370       if(aNewShell.ShapeType()!= TopAbs_SHELL) {
371         aSeqShapes.Append(aNewShell);
372         continue;
373       }
374       TopoDS_Shape as = getResultShell(TopoDS::Shell(aNewShell));
375       isChange = (as.IsNull() || (as.ShapeType() == TopAbs_FACE));
376       if(!as.IsNull()) {
377         aSeqShapes.Append(as);
378       }
379     }
380   }
381   else if(theShape.ShapeType() == TopAbs_SHELL) {
382     TopoDS_Shape aSh = getResultShell(TopoDS::Shell(theShape));
383     isChange = (aSh.IsNull() || (aSh.ShapeType() == TopAbs_FACE));
384     if(!aSh.IsNull())
385       aSeqShapes.Append(aSh);
386   }
387   else aSeqShapes.Append(theShape);
388
389   if(aSeqShapes.IsEmpty())
390     return Standard_True;
391
392   if(isChange) {
393     if(aSeqShapes.Length() == 1)
394       theNewShape = aSeqShapes.Value(1);
395     else if (aSeqShapes.Length() > 1) {
396       TopoDS_Compound aComp1;
397       BRep_Builder aBB;
398       aBB.MakeCompound(aComp1);
399       Standard_Integer kk =1;
400       for( ; kk <=  aSeqShapes.Length(); kk++)
401         aBB.Add(aComp1,aSeqShapes.Value(kk));
402       if(aSeqShapes.Length())
403         theNewShape = aComp1;
404     }
405   }
406   else
407     theNewShape = theShape;
408   return isChange;
409 }
410 //=======================================================================
411 //function : removePCurve
412 //purpose  : 
413 //=======================================================================
414
415 void ShHealOper_RemoveFace::removePCurve(const TopoDS_Face& theFace)
416 {
417   //removing pcurves belonging removed face.
418   Handle(Geom_Surface) aSurfDel = BRep_Tool::Surface(theFace);
419   for(TopExp_Explorer aExpEdges(theFace,TopAbs_EDGE);  aExpEdges.More();  aExpEdges.Next()) {
420     const TopTools_ListOfShape& alFaces = myMapEdgesFace.FindFromKey(aExpEdges.Current());
421     Standard_Boolean aIsDeleted = Standard_True;
422     
423     //pcurve will be removed if containing this edge faces have different surfaces.
424     TopTools_ListIteratorOfListOfShape aIterOtherFace(alFaces);
425     for(; aIterOtherFace.More() && aIsDeleted ; aIterOtherFace.Next()) {
426       if(aIterOtherFace.Value().IsSame(theFace))
427          continue;
428          TopoDS_Face aFaceOther = TopoDS::Face(aIterOtherFace.Value());
429          Handle(Geom_Surface) aSurf = BRep_Tool::Surface( aFaceOther);
430          aIsDeleted = (aSurf != aSurfDel);
431     }
432     
433     TopoDS_Edge aEdge = TopoDS::Edge(myContext->Apply(aExpEdges.Current()));
434     ShapeBuild_Edge aSbe;
435     TopoDS_Edge aNewEdge = aSbe.Copy(aEdge,Standard_False);
436     if(aIsDeleted) {
437       aSbe.RemovePCurve(aNewEdge,aSurfDel);
438       myContext->Replace(aEdge,aNewEdge);
439       
440     }
441     
442   }
443 }
444