Salome HOME
Merge with version on tag OCC-V2_1_0d
[modules/geom.git] / src / ShHealOper / ShHealOper_RemoveFace.cxx
diff --git a/src/ShHealOper/ShHealOper_RemoveFace.cxx b/src/ShHealOper/ShHealOper_RemoveFace.cxx
new file mode 100644 (file)
index 0000000..3501fe0
--- /dev/null
@@ -0,0 +1,444 @@
+// File:      ShHealOper_RemoveFace.cxx
+// Created:   16.04.04 12:12:38
+// Author:    Galina KULIKOVA
+//  < MODULE = KERNEL> <PACKAGE = ShHealOper> : <Shape Healing Operations>
+//  Copyright (C) 2003  CEA
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2.1 of the License.
+//
+
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+
+#include <ShHealOper_RemoveFace.hxx>
+#include <BRepTools_ReShape.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopAbs_ShapeEnum.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopoDS_Solid.hxx>
+#include <TopoDS_Shell.hxx>
+#include <TopoDS_Face.hxx>
+#include <BRep_Builder.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopExp.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_Surface.hxx>
+#include <TopoDS_Edge.hxx>
+#include <ShapeBuild_Edge.hxx>
+#include <ShapeFix_Shell.hxx>
+#include <ShapeFix_Solid.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+
+
+//=======================================================================
+//function : ShHealOper_RemoveFace()
+//purpose  : Constructor
+//=======================================================================
+ShHealOper_RemoveFace::ShHealOper_RemoveFace () :
+       ShHealOper_Tool()
+{
+}
+//=======================================================================
+//function : ShHealOper_RemoveFace
+//purpose  : 
+//=======================================================================
+
+ShHealOper_RemoveFace::ShHealOper_RemoveFace ( const TopoDS_Shape& theShape ) 
+       //ShHealOper_Tool(theShape)
+{
+  Init(theShape);
+}
+//=======================================================================
+//function : Init
+//purpose  : 
+//=======================================================================
+
+void ShHealOper_RemoveFace::Init(const TopoDS_Shape& theShape)
+{
+  //myDone = Standard_False;
+  //myInitShape = theShape;
+  //myContext->Apply(myInitShape);
+  ShHealOper_Tool::Init(theShape);
+  myMapEdgesFace.Clear();
+  TopExp::MapShapesAndAncestors(theShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgesFace);
+}
+//=======================================================================
+//function : Perform
+//purpose  : remove all faces from initial shape
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::Perform()
+{
+  myDone = Standard_False;
+  myErrorStatus = ShHealOper_NotError;
+  if(myInitShape.IsNull()) {
+    myErrorStatus = ShHealOper_InvalidParameters;
+    return myDone;
+  }
+  TopExp_Explorer aExp(myInitShape,TopAbs_FACE);
+  for( ; aExp.More(); aExp.Next()) {
+    removePCurve(TopoDS::Face(aExp.Current()));
+    myContext->Remove(aExp.Current());
+    myDone = Standard_True;
+  }
+  if(myDone) {
+    TopoDS_Shape aNewShape = myContext->Apply(myInitShape);
+    isReplace(aNewShape,myResultShape);
+    myContext->Replace(aNewShape,myResultShape);
+  }
+  return myDone;
+}
+//=======================================================================
+//function : Perform
+//purpose  : remove faces specified by sequence of faces from initial shape.
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::Perform(const TopTools_SequenceOfShape& theRemoveFaces)
+{
+  myDone = Standard_False;
+  myErrorStatus = ShHealOper_NotError;
+  if(myInitShape.IsNull()) {
+    myErrorStatus = ShHealOper_InvalidParameters;
+    return myDone;
+  }
+  if(theRemoveFaces.IsEmpty())
+    return Standard_False;
+  myMapFaces.Clear();
+  
+  Standard_Integer i=1; 
+  for( ; i <= theRemoveFaces.Length(); i++)
+    myMapFaces.Add(theRemoveFaces.Value(i));
+  
+  myDone = removeFaces(myInitShape,myResultShape);
+  return myDone;
+}
+
+//=======================================================================
+//function : removeFaces
+//purpose  : 
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Shape& theShape,
+                                                    TopoDS_Shape& theNewShape)
+{
+  Standard_Boolean isDone = Standard_False;
+  
+  TopAbs_ShapeEnum aType = theShape.ShapeType();
+  theNewShape = theShape;
+  if(!myMapFaces.Extent())
+    return isDone;
+  if( aType == TopAbs_WIRE || aType == TopAbs_EDGE || aType == TopAbs_VERTEX)
+      return isDone;
+  if(aType == TopAbs_FACE && myMapFaces.Contains(theShape)) {
+    removePCurve(TopoDS::Face(theShape));
+    
+    myContext->Remove(theShape);
+    myMapFaces.Remove(theShape);
+    //theNewShape = TopoDS_Shape();
+    theNewShape.Nullify();
+    isDone = Standard_True;
+  }
+  else if(aType == TopAbs_SHELL) {
+    isDone = removeFaces(TopoDS::Shell(theShape),theNewShape);
+    return isDone;
+  }
+  else if(aType == TopAbs_SOLID) {
+    isDone = removeFaces(TopoDS::Solid(theShape),theNewShape);
+    myContext->Replace(theShape,theNewShape);
+  }
+  else if(aType == TopAbs_COMPSOLID) {
+
+    //in the case of compsolid method for removing faces for solid
+    //will be used.
+
+    TopExp_Explorer aExpShell(theShape,TopAbs_SHELL);
+    TopoDS_Solid aSol;
+    BRep_Builder aB;
+    aB.MakeSolid(aSol);
+    for( ; aExpShell.More(); aExpShell.Next()) {
+      aB.Add(aSol,aExpShell.Current());
+    }
+    TopoDS_Shape aNewShape;
+    isDone =  removeFaces(aSol,aNewShape);
+    if(isDone)
+       myContext->Replace(theShape,theNewShape);
+    
+  }
+  else if(aType == TopAbs_COMPOUND) {
+    //in the case of compounf faces will be removed from each part of compound separately
+
+    TopoDS_Compound aComp;
+    TopoDS_Iterator aItShape(theShape,Standard_False);
+    BRep_Builder aB;
+    aB.MakeCompound(aComp);
+    Standard_Integer nbs =0;
+    for( ; aItShape.More() ; aItShape.Next()) {
+
+      TopoDS_Shape aNShape;
+      if( removeFaces(aItShape.Value(),aNShape)) {
+        isDone = Standard_True;
+        myContext->Replace(aItShape.Value(),aNShape);
+      }
+      if(!aNShape.IsNull()) {
+        aB.Add(aComp,aNShape);
+        nbs++;
+      }
+    }
+    if(isDone) {
+      if(nbs) 
+        theNewShape = aComp;
+      else
+        theNewShape =TopoDS_Shape();
+      myContext->Replace(theShape,theNewShape);
+    }
+   
+  }
+  return isDone;
+}
+//=======================================================================
+//function : removeFaces
+//purpose  : function for removing faces from solid
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Solid& theShape,
+                                                    TopoDS_Shape& theNewShape)
+{
+  Standard_Boolean isDone = Standard_False;
+  TopoDS_Solid aSol;
+  BRep_Builder aB;
+  aB.MakeSolid(aSol);
+  TopoDS_Compound aComp;
+  aB.MakeCompound(aComp);
+  Standard_Boolean isAddSol = Standard_False, isAddComp = Standard_False;
+
+  //firslty faces will be deleted from each shell.
+  TopoDS_Iterator aItSol(theShape,Standard_False);
+  for( ; aItSol.More(); aItSol.Next()) {
+    TopoDS_Shape aSh = aItSol.Value();
+    TopoDS_Shape aNewShape;
+    if(removeFaces(aSh,aNewShape)) 
+      isDone = Standard_True;
+    
+    if(aNewShape.IsNull())
+      continue;
+    else if(aNewShape.ShapeType() == TopAbs_SHELL ) {
+      aB.Add(aSol,aNewShape);
+      isAddSol = Standard_True;
+    }
+    else {
+      aB.Add(aComp,aNewShape);
+      isAddComp = Standard_True;
+    }
+    
+  }
+  if(isDone) {
+    //for getting correct solids class ShapeFix_Solid will be used.
+    if(isAddSol) {
+      Handle(ShapeFix_Solid) aSfSol = new ShapeFix_Solid(aSol);
+      aSfSol->FixShellMode()= Standard_False;
+      aSfSol->Perform();
+      TopoDS_Shape aresSol = aSfSol->Shape();
+      if(!isAddComp) 
+        theNewShape = aresSol;
+      else 
+        aB.Add(aComp,aresSol);
+    }
+    else if(isAddComp)
+        theNewShape = aComp;
+    else
+      theNewShape.Nullify();
+  }
+  else
+    theNewShape = theShape; 
+  return isDone;
+}
+//=======================================================================
+//function : IsManifold
+//purpose  : function for definition manifold shell
+//=======================================================================
+Standard_Boolean ShHealOper_RemoveFace::isManifold(const TopoDS_Shell& aShell)
+{
+  Standard_Boolean IsManifold = Standard_True;
+  TopExp_Explorer aExp(aShell,TopAbs_EDGE);
+  for( ; aExp.More() && IsManifold; aExp.Next()) {
+    const TopTools_ListOfShape& als = myMapEdgesFace.FindFromKey(aExp.Current());
+    IsManifold = (als.Extent() <=2 ); 
+  }
+  return IsManifold;
+}
+
+//=======================================================================
+//function : getResultShell
+//purpose  : function for avoiding empty shall or shell containing one face.
+//=======================================================================
+static TopoDS_Shape getResultShell(const TopoDS_Shape& theNewShell)
+{
+  TopoDS_Shape rs;
+  Standard_Integer NbFacesShell =0;
+  TopoDS_Shape aF;
+  TopoDS_Iterator aI(theNewShell,Standard_False);
+  for(; aI.More(); aI.Next(),NbFacesShell++)
+    aF = aI.Value();
+  if(NbFacesShell >1)
+    rs = theNewShell;
+  else if(!aF.IsNull())
+    rs = aF;
+  return rs;
+}
+
+//=======================================================================
+//function : removeFaces
+//purpose  : function for removing faces from shell
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::removeFaces(const TopoDS_Shell& theShell,
+                                                    TopoDS_Shape& theNewShape)
+{
+  
+  Standard_Boolean aIsRemove = Standard_False;
+  //TopoDS_Shape aShape = myReShape->Apply(theShape);
+  //removing faces from shell.
+  TopoDS_Iterator aIterFaces(theShell,Standard_False);
+  for(; aIterFaces.More() && myMapFaces.Extent(); aIterFaces.Next()) {
+
+    if(!myMapFaces.Contains(aIterFaces.Value()))
+      continue;
+    TopoDS_Face aFace = TopoDS::Face( aIterFaces.Value());
+    removePCurve(aFace);
+    aIsRemove  = Standard_True;
+    myContext->Remove(aFace);
+    myMapFaces.Remove(aFace);
+  }
+  if(aIsRemove) {
+    TopoDS_Shape aNewShape = myContext->Apply(theShell);
+    //avoiding empty shell and shell containing one face.
+    TopoDS_Shape aresShape = getResultShell(aNewShape);
+    if(aresShape.IsNull()) {
+      myContext->Remove(aNewShape);
+      theNewShape.Nullify();
+    }
+    else if(aresShape.ShapeType() == TopAbs_FACE) {
+      myContext->Replace(aNewShape,aresShape);
+      theNewShape = aresShape;
+    }
+    else if(aresShape.ShapeType() == TopAbs_SHELL) {
+      //obtaining correct shell or compound with help class ShapeFix_Shell.
+      Standard_Boolean isManifShell = isManifold(theShell);
+      Handle(ShapeFix_Shell) aFixShell = new ShapeFix_Shell;
+      aFixShell->FixFaceOrientation(TopoDS::Shell(aresShape),Standard_True,!isManifShell);
+      TopoDS_Shape aFixShape = aFixShell->Shape();
+      TopoDS_Shape areplShape;
+      isReplace(aFixShape,areplShape);
+      myContext->Replace(aNewShape,areplShape);
+      theNewShape = areplShape;
+    }
+  }
+  else theNewShape = theShell;
+  return aIsRemove;
+}
+//=======================================================================
+//function : isReplace
+//purpose  : method to avoiding empty compounds and shells.
+//=======================================================================
+
+Standard_Boolean ShHealOper_RemoveFace::isReplace(const TopoDS_Shape& theShape, 
+                                                  TopoDS_Shape& theNewShape)
+{
+  
+  Standard_Boolean isChange = Standard_False;
+  TopTools_SequenceOfShape aSeqShapes;
+  if(theShape.ShapeType() == TopAbs_COMPOUND || theShape.ShapeType() == TopAbs_COMPSOLID ||
+     theShape.ShapeType() == TopAbs_SOLID) {
+    TopoDS_Iterator aEs(theShape);
+    for( ; aEs.More(); aEs.Next()) {
+      TopoDS_Shape aNewShell = aEs.Value();
+      if(aNewShell.ShapeType()!= TopAbs_SHELL) {
+        aSeqShapes.Append(aNewShell);
+        continue;
+      }
+      TopoDS_Shape as = getResultShell(TopoDS::Shell(aNewShell));
+      isChange = (as.IsNull() || (as.ShapeType() == TopAbs_FACE));
+      if(!as.IsNull()) {
+        aSeqShapes.Append(as);
+      }
+    }
+  }
+  else if(theShape.ShapeType() == TopAbs_SHELL) {
+    TopoDS_Shape aSh = getResultShell(TopoDS::Shell(theShape));
+    isChange = (aSh.IsNull() || (aSh.ShapeType() == TopAbs_FACE));
+    if(!aSh.IsNull())
+      aSeqShapes.Append(aSh);
+  }
+  else aSeqShapes.Append(theShape);
+
+  if(aSeqShapes.IsEmpty())
+    return Standard_True;
+
+  if(isChange) {
+    if(aSeqShapes.Length() == 1)
+      theNewShape = aSeqShapes.Value(1);
+    else if (aSeqShapes.Length() > 1) {
+      TopoDS_Compound aComp1;
+      BRep_Builder aBB;
+      aBB.MakeCompound(aComp1);
+      Standard_Integer kk =1;
+      for( ; kk <=  aSeqShapes.Length(); kk++)
+        aBB.Add(aComp1,aSeqShapes.Value(kk));
+      if(aSeqShapes.Length())
+        theNewShape = aComp1;
+    }
+  }
+  else
+    theNewShape = theShape;
+  return isChange;
+}
+//=======================================================================
+//function : removePCurve
+//purpose  : 
+//=======================================================================
+
+void ShHealOper_RemoveFace::removePCurve(const TopoDS_Face& theFace)
+{
+  //removing pcurves belonging removed face.
+  Handle(Geom_Surface) aSurfDel = BRep_Tool::Surface(theFace);
+  for(TopExp_Explorer aExpEdges(theFace,TopAbs_EDGE);  aExpEdges.More();  aExpEdges.Next()) {
+    const TopTools_ListOfShape& alFaces = myMapEdgesFace.FindFromKey(aExpEdges.Current());
+    Standard_Boolean aIsDeleted = Standard_True;
+    
+    //pcurve will be removed if containing this edge faces have different surfaces.
+    TopTools_ListIteratorOfListOfShape aIterOtherFace(alFaces);
+    for(; aIterOtherFace.More() && aIsDeleted ; aIterOtherFace.Next()) {
+      if(aIterOtherFace.Value().IsSame(theFace))
+         continue;
+         TopoDS_Face aFaceOther = TopoDS::Face(aIterOtherFace.Value());
+         Handle(Geom_Surface) aSurf = BRep_Tool::Surface( aFaceOther);
+         aIsDeleted = (aSurf != aSurfDel);
+    }
+    
+    TopoDS_Edge aEdge = TopoDS::Edge(myContext->Apply(aExpEdges.Current()));
+    ShapeBuild_Edge aSbe;
+    TopoDS_Edge aNewEdge = aSbe.Copy(aEdge,Standard_False);
+    if(aIsDeleted) {
+      aSbe.RemovePCurve(aNewEdge,aSurfDel);
+      myContext->Replace(aEdge,aNewEdge);
+      
+    }
+    
+  }
+}
+