0031460: Modeling Algorithms - Regression: Revolution not done.
[occt.git] / src / BRepPrimAPI / BRepPrimAPI_MakeRevol.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 849418b..a6aed7d
@@ -1,35 +1,39 @@
 // Created on: 1993-10-14
 // Created by: Remi LEQUETTE
 // Copyright (c) 1993-1999 Matra Datavision
-// Copyright (c) 1999-2012 OPEN CASCADE SAS
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
 //
-// The content of this file is subject to the Open CASCADE Technology Public
-// License Version 6.5 (the "License"). You may not use the content of this file
-// except in compliance with the License. Please obtain a copy of the License
-// at http://www.opencascade.org and read it completely before using this file.
+// This file is part of Open CASCADE Technology software library.
 //
-// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
-// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
 //
-// The Original Code and all software distributed under the License is
-// distributed on an "AS IS" basis, without warranty of any kind, and the
-// Initial Developer hereby disclaims all such warranties, including without
-// limitation, any warranties of merchantability, fitness for a particular
-// purpose or non-infringement. Please see the License for the specific terms
-// and conditions governing the rights and limitations under the License.
-
-
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
 
 // Modified by skv - Fri Mar  4 15:50:09 2005
 // Add methods for supporting history.
 
-#include <BRepPrimAPI_MakeRevol.ixx>
+#include <BRep_TEdge.hxx>
 #include <BRepLib.hxx>
+#include <BRepPrimAPI_MakeRevol.hxx>
+#include <BRepSweep_Revol.hxx>
+#include <gp_Ax1.hxx>
 #include <TopExp_Explorer.hxx>
-#include <BRep_TEdge.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#include <BRepTools_ReShape.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <GeomAdaptor_SurfaceOfRevolution.hxx>
+#include <GeomAdaptor_HCurve.hxx>
+#include <Extrema_ExtCC.hxx>
+#include <Extrema_POnCurv.hxx>
+#include <Geom_Line.hxx>
 
 // perform checks on the argument
-
 static const TopoDS_Shape& check(const TopoDS_Shape& S)
 {
  BRepLib::BuildCurves3d(S);
@@ -44,10 +48,20 @@ static const TopoDS_Shape& check(const TopoDS_Shape& S)
 BRepPrimAPI_MakeRevol::BRepPrimAPI_MakeRevol(const TopoDS_Shape& S, 
                                     const gp_Ax1& A, 
                                     const Standard_Real D, 
-                                    const Standard_Boolean Copy) :
-       myRevol(check(S),A,D,Copy)
+             const Standard_Boolean Copy) : 
+             myRevol(check(S), A, D, Copy),
+             myIsBuild(Standard_False)
+
 {
-  Build();
+  if (!CheckValidity(check(S), A))
+  {
+    myShape.Nullify();
+    myIsBuild = Standard_True;
+  }
+  else
+  {
+    Build();
+  }
 }
 
 
@@ -58,10 +72,21 @@ BRepPrimAPI_MakeRevol::BRepPrimAPI_MakeRevol(const TopoDS_Shape& S,
 
 BRepPrimAPI_MakeRevol::BRepPrimAPI_MakeRevol(const TopoDS_Shape& S, 
                                     const gp_Ax1& A, 
-                                    const Standard_Boolean Copy) :
-       myRevol(check(S),A,Copy)
+             const Standard_Boolean Copy) :
+             
+             myRevol(check(S), A, 2. * M_PI, Copy),
+              myIsBuild(Standard_False)
 {
-  Build();
+
+  if (!CheckValidity(check(S), A))
+  {
+    myShape.Nullify();
+    myIsBuild = Standard_True;
+  }
+  else
+  {
+    Build();
+  }
 }
 
 
@@ -83,21 +108,247 @@ const BRepSweep_Revol&  BRepPrimAPI_MakeRevol::Revol() const
 
 void  BRepPrimAPI_MakeRevol::Build()
 {
+  if (myIsBuild)
+  {
+    return;
+  }
   myShape = myRevol.Shape();
+  BRepLib::UpdateInnerTolerances(myShape);
+  
   Done();
-// Modified by skv - Fri Mar  4 15:50:09 2005 Begin
+  myIsBuild = Standard_True;
+
+  myHist.Nullify();
   myDegenerated.Clear();
+  TopTools_DataMapOfShapeListOfShape aDegE;
+  BRep_Builder aBB;
 
   TopExp_Explorer anExp(myShape, TopAbs_EDGE);
-
+  //Problem is that some degenerated edges can be shared by different faces.
+  //It is not valid for correct shape.
+  //To solve problem it is possible to copy shared degenerated edge for each face, which has it, and 
+  //replace shared edge by its copy
   for (; anExp.More(); anExp.Next()) {
     const TopoDS_Shape &anEdge = anExp.Current();
     Handle(BRep_TEdge)  aTEdge = Handle(BRep_TEdge)::DownCast(anEdge.TShape());
 
     if (aTEdge->Degenerated())
-      myDegenerated.Append(anEdge);
+    {
+      TopTools_ListOfShape* anL = aDegE.ChangeSeek(anEdge);
+      if (anL)
+      {
+        //Make the copy if degenerated edge occurs more then once
+        TopoDS_Shape aCopyE = anEdge.EmptyCopied();
+        aCopyE.Orientation(TopAbs_FORWARD);
+        TopoDS_Iterator aVIter(anEdge.Oriented(TopAbs_FORWARD), Standard_False);
+        for (; aVIter.More(); aVIter.Next())
+        {
+          aBB.Add(aCopyE, aVIter.Value());
+        }
+        aCopyE.Orientation(anEdge.Orientation());
+        anL->Append(aCopyE);
+        myDegenerated.Append(aCopyE);
+      }
+      else
+      {
+        anL = aDegE.Bound(anEdge, TopTools_ListOfShape());
+        anL->Append(anEdge);
+        myDegenerated.Append(anEdge);
+      }
+    }
+  }
+  if (!myDegenerated.IsEmpty())
+  {
+    BRepTools_ReShape aSubs;
+    TopTools_DataMapOfShapeListOfShape aDegF;
+    Standard_Boolean isReplaced = Standard_False;
+    anExp.Init(myShape, TopAbs_FACE);
+    //Replace degenerated edge by its copies for different faces
+    //First, for each face list of d.e. is created
+    for (; anExp.More(); anExp.Next())
+    {
+      const TopoDS_Shape& aF = anExp.Current();
+      TopExp_Explorer anExpE(aF, TopAbs_EDGE);
+      for (; anExpE.More(); anExpE.Next())
+      {
+        const TopoDS_Shape &anE = anExpE.Current();
+        if (BRep_Tool::Degenerated(TopoDS::Edge(anE)))
+        {
+          TopTools_ListOfShape* anL = aDegF.ChangeSeek(aF);
+          if (!anL)
+          {
+            anL = aDegF.Bound(aF, TopTools_ListOfShape());
+          }
+          anL->Append(anE);
+        }
+      }
+    }
+    //
+    //Second, replace edges by copies using ReShape
+    BRepTools_ReShape aSubsF;
+    TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aFIter(aDegF);
+    for (; aFIter.More(); aFIter.Next())
+    {
+      aSubs.Clear();
+      isReplaced = Standard_False;
+      const TopoDS_Shape& aF = aFIter.Key();
+      const TopTools_ListOfShape& aDEL = aFIter.ChangeValue();
+      TopTools_ListIteratorOfListOfShape anEIter(aDEL);
+      for (; anEIter.More(); anEIter.Next())
+      {
+        const TopoDS_Shape& anE = anEIter.Value();
+        if (aDegE.IsBound(anE))
+        {
+          TopTools_ListOfShape& aCEL = aDegE.ChangeFind(anE);
+          TopTools_ListIteratorOfListOfShape anIt(aCEL);
+          for (; anIt.More(); anIt.Next())
+          {
+            if (anIt.Value().IsEqual(anE))
+            {
+              //First occurence of initial deg. edge is not replaced
+              aCEL.Remove(anIt);
+              break;
+            }
+            if (anIt.Value().Orientation() == anE.Orientation())
+            {
+              //All other occurences of anE are replaced by any copy
+              //with suitable orientation
+              isReplaced = Standard_True;
+              aSubs.Replace(anE, anIt.Value());
+              aCEL.Remove(anIt);
+              break;
+            }
+          }
+        }
+      }
+      if (isReplaced)
+      {
+        TopoDS_Shape aNF = aSubs.Apply(aF);
+        aSubsF.Replace(aF, aNF);
+        if (myHist.IsNull())
+        {
+          myHist = aSubs.History();
+        }
+        else
+        {
+          myHist->Merge(aSubs.History());
+        }
+        myShape = aSubsF.Apply(myShape);
+        myHist->Merge(aSubsF.History());
+        //Pair aF->aNF is in history after first replacing of edge by aNF = aSubs.Apply(aF)
+        //After merging history for replacing faces, modified list for aF contains two exemplar of aNF
+        //So, using ReplaceModified clears modified list for aF and leaves only one exemplar of aNF
+        myHist->ReplaceModified(aF, aNF);
+        aSubsF.Clear();
+      }
+    }
+  }
+}
+//=======================================================================
+//function : IsIntersect
+//purpose  : used in CheckValidity to find out is there
+//           intersection between curve and axe of revolution
+//=======================================================================
+static Standard_Boolean IsIntersect(const Handle(Adaptor3d_HCurve)& theC, 
+                                    const gp_Ax1& theAxe)
+{
+  const gp_Lin anAxis(theAxe);
+  //Quick test for circle
+  if (theC->GetType() == GeomAbs_Circle)
+  {
+    gp_Circ aCirc = theC->Circle();
+    const gp_Pnt& aCentr = aCirc.Location();
+    Standard_Real anR2 = aCirc.Radius();
+    anR2 -= Precision::Confusion();
+    anR2 *= anR2;
+    if (anAxis.SquareDistance(aCentr) > anR2)
+    {
+      return Standard_False;
+    }
+  }
+  const Handle(Geom_Line) aL = new Geom_Line(anAxis);
+  const GeomAdaptor_Curve aLin(aL);
+  const Standard_Real aParTol = theC->Resolution(Precision::Confusion());
+  const Standard_Real aParF = theC->FirstParameter() + aParTol,
+                      aParL = theC->LastParameter() - aParTol;
+
+  Extrema_ExtCC anExtr(theC->Curve(), aLin);
+  anExtr.Perform();
+  if (anExtr.IsDone() && anExtr.NbExt() > 0)
+  {
+    Extrema_POnCurv aP1, aP2;
+    for (Standard_Integer i = 1; i <= anExtr.NbExt(); i++)
+    {
+      if (anExtr.SquareDistance(i) > Precision::SquareConfusion())
+      {
+        continue;
+      }
+      anExtr.Points(i, aP1, aP2);
+      if ((aParF < aP1.Parameter()) && (aP1.Parameter() < aParL))
+      {
+        return Standard_True;
+      }
+    }
   }
-// Modified by skv - Fri Mar  4 15:50:09 2005 End
+  return Standard_False;
+}
+
+//=======================================================================
+//function : CheckValidity
+//purpose  : 
+//=======================================================================
+
+Standard_Boolean BRepPrimAPI_MakeRevol::CheckValidity(const TopoDS_Shape& theShape,
+                                                      const gp_Ax1& theA)
+{
+  TopExp_Explorer anExp(theShape, TopAbs_EDGE);
+  Standard_Boolean IsValid = Standard_True;
+  for (; anExp.More(); anExp.Next())
+  {
+    const TopoDS_Edge& anE = TopoDS::Edge(anExp.Current());
+
+    if (BRep_Tool::Degenerated(anE))
+    {
+      continue;
+    }
+
+    TopLoc_Location L;
+    Standard_Real First, Last;
+    Handle(Geom_Curve) C = BRep_Tool::Curve(anE, L, First, Last);
+    gp_Trsf Tr = L.Transformation();
+    C = Handle(Geom_Curve)::DownCast(C->Copy());
+    C = new Geom_TrimmedCurve(C, First, Last);
+    C->Transform(Tr);
+
+    Handle(GeomAdaptor_HCurve) HC = new GeomAdaptor_HCurve();
+    HC->ChangeCurve().Load(C, First, Last);
+    //Checking coinsidence axe of revolution and basis curve
+    //This code is taken directly from GeomAdaptor_SurfaceOfRevolution
+    Standard_Integer Ratio = 1;
+    Standard_Real Dist;
+    gp_Pnt PP;
+    do {
+      PP = HC->Value(First + (Last - First) / Ratio);
+      Dist = gp_Lin(theA).Distance(PP);
+      Ratio++;
+    } while (Dist < Precision::Confusion() && Ratio < 100);
+    //
+    if (Ratio >= 100) // edge coinsides with axes
+    {
+      IsValid = Standard_True; //Such edges are allowed by revol algo and treated
+                               //by special way, so they must be concidered as valid
+    }
+    else
+    {
+      IsValid = !IsIntersect(HC, theA);
+    }
+    if (!IsValid)
+    {
+      break;
+    }
+  }
+  //
+  return IsValid;
 }
 
 
@@ -122,23 +373,81 @@ TopoDS_Shape BRepPrimAPI_MakeRevol::LastShape()
   return myRevol.LastShape();
 }
 
-
 //=======================================================================
 //function : Generated
 //purpose  : 
 //=======================================================================
-
 const TopTools_ListOfShape& BRepPrimAPI_MakeRevol::Generated (const TopoDS_Shape& S)
 {
   myGenerated.Clear();
-  if (!myRevol.Shape (S).IsNull())
-    myGenerated.Append (myRevol.Shape (S));
+
+  if (!myRevol.IsUsed(S))
+  {
+    return myGenerated;
+  }
+
+  TopoDS_Shape aGS = myRevol.Shape(S);
+  if (!aGS.IsNull())
+  { 
+    if (BRepTools_History::IsSupportedType(aGS))
+    {
+      if (aGS.ShapeType() == TopAbs_EDGE)
+      {
+        Standard_Boolean isDeg = BRep_Tool::Degenerated(TopoDS::Edge(aGS));
+        if (isDeg)
+        {
+          TopTools_ListIteratorOfListOfShape anIt(myDegenerated);
+          for (; anIt.More(); anIt.Next())
+          {
+            if (aGS.IsSame(anIt.Value()))
+            {
+              myGenerated.Append(aGS);
+              if (!myHist.IsNull())
+              {
+                TopTools_ListIteratorOfListOfShape anIt1(myHist->Modified(aGS));
+                for (; anIt1.More(); anIt1.Next())
+                {
+                  myGenerated.Append(anIt1.Value());
+                }
+                return myGenerated;
+              }
+            }
+          }
+          return myGenerated;
+        }
+      }
+      //
+      if (myHist.IsNull())
+      {
+        myGenerated.Append(aGS);
+        return myGenerated;
+      }
+      //
+      if (myHist->Modified(aGS).IsEmpty())
+      {
+        myGenerated.Append(aGS);
+        return myGenerated;
+      }
+      //
+      TopTools_ListIteratorOfListOfShape anIt(myHist->Modified(aGS));
+      for (; anIt.More(); anIt.Next())
+      {
+        myGenerated.Append(anIt.Value());
+      }
+    }
+  }
   return myGenerated;
 }
+//=======================================================================
+//function : IsDeleted
+//purpose  : 
+//=======================================================================
+Standard_Boolean BRepPrimAPI_MakeRevol::IsDeleted(const TopoDS_Shape& S)
+{
+  return !myRevol.IsUsed(S);
+}
 
 
-// Modified by skv - Fri Mar  4 15:50:09 2005 Begin
-
 //=======================================================================
 //function : FirstShape
 //purpose  : This method returns the shape of the beginning of the revolution,
@@ -182,4 +491,3 @@ const TopTools_ListOfShape& BRepPrimAPI_MakeRevol::Degenerated () const
 {
   return myDegenerated;
 }
-// Modified by skv - Fri Mar  4 15:50:09 2005 End