Salome HOME
0023505: Sigsegv with fuse on cylinder and cone
[modules/geom.git] / src / GEOMImpl / GEOMImpl_ProjectionDriver.cxx
index e8fa499b5e952046cc1a76d9e8f7cd47d2bd7f6b..5195bb8c874facbf666c3d8e624c6f4a1bbef145 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // 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.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 #include <GEOMImpl_IMirror.hxx>
 #include <GEOMImpl_IProjection.hxx>
+#include <GEOMImpl_IProjOnCyl.hxx>
 #include <GEOMImpl_Types.hxx>
 #include <GEOM_Function.hxx>
+#include <GEOMUtils.hxx>
+#include <GEOMUtils_HTrsfCurve2d.hxx>
 
+#include <Approx_Curve2d.hxx>
+#include <Bnd_Box2d.hxx>
+#include <BndLib_Add2dCurve.hxx>
 #include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve2d.hxx>
 #include <BRepBuilderAPI_Transform.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
 #include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepClass_FaceClassifier.hxx>
 #include <BRepExtrema_DistShapeShape.hxx>
+#include <BRepLib.hxx>
 #include <BRepOffsetAPI_NormalProjection.hxx>
 #include <BRepTools.hxx>
+#include <BRepTools_WireExplorer.hxx>
 
 #include <TopAbs.hxx>
 #include <TopExp.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Vertex.hxx>
-#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
 
 #include <GeomAPI_ProjectPointOnSurf.hxx>
 #include <Geom_Curve.hxx>
+#include <Geom_CylindricalSurface.hxx>
 #include <Geom_Plane.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
 
 #include <gp_Trsf.hxx>
 #include <gp_Pnt.hxx>
@@ -78,7 +93,7 @@ GEOMImpl_ProjectionDriver::GEOMImpl_ProjectionDriver()
 //function : Execute
 //purpose  :
 //======================================================================= 
-Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) const
+Standard_Integer GEOMImpl_ProjectionDriver::Execute(Handle(TFunction_Logbook)& log) const
 {
   if (Label().IsNull())  return 0;    
   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
@@ -145,7 +160,7 @@ Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) cons
         Standard_ConstructionError::Raise("No solution found");
       }
 
-      Quantity_Parameter U, V;
+      Standard_Real U, V;
       proj.LowerDistanceParameters(U, V);
       gp_Pnt2d aProjPnt (U, V);
 
@@ -155,7 +170,7 @@ Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) cons
         bool isSol = false;
         double minDist = RealLast();
         for (int i = 1; i <= nbPoints; i++) {
-          Quantity_Parameter Ui, Vi;
+          Standard_Real Ui, Vi;
           proj.Parameters(i, Ui, Vi);
           aProjPnt = gp_Pnt2d(Ui, Vi);
           aClsf.Perform(aFace, aProjPnt, tol);
@@ -183,17 +198,30 @@ Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) cons
       BRepOffsetAPI_NormalProjection OrtProj (aFaceShape);
       OrtProj.Add(anOriginal);
 
-      //Standard_Real tol = 1.e-4;        
-      //Standard_Real tol2d = Pow(tol, 2./3);
-      //GeomAbs_Shape Continuity = GeomAbs_C2;  
-      //Standard_Integer MaxDeg = 14;           
-      //Standard_Integer MaxSeg = 16;           
-      //OrtProj.SetParams(tol, tol2d, Continuity, MaxDeg, MaxSeg);
+      // Compute maximal tolerance of projection.
+      TopExp_Explorer anExp(anOriginal,TopAbs_VERTEX);
+      Standard_Real   aMaxTol = Precision::Confusion();
+
+      for(; anExp.More(); anExp.Next()) { 
+        const TopoDS_Vertex aVtx    = TopoDS::Vertex(anExp.Current());
+        const Standard_Real aCurTol = BRep_Tool::Tolerance(aVtx);
+
+        if (aMaxTol < aCurTol) {
+          aMaxTol = aCurTol;
+        }
+      }
+
+      Standard_Real tol2d = Pow(aMaxTol, 2./3);
+      GeomAbs_Shape Continuity = GeomAbs_C2;
+      Standard_Integer MaxDeg = 14;
+      Standard_Integer MaxSeg = 16;
+
+      OrtProj.SetParams(aMaxTol, tol2d, Continuity, MaxDeg, MaxSeg);
+
       try {
         OrtProj.Build();
-      } catch (Standard_Failure) {
-        Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-        TCollection_AsciiString aMsg (aFail->GetMessageString());
+      } catch (Standard_Failure& aFail) {
+        TCollection_AsciiString aMsg (aFail.GetMessageString());
         if (!aMsg.Length())
           aMsg = "Projection aborted : possibly the source shape intersects the cylinder's axis";
         Standard_ConstructionError::Raise(aMsg.ToCString());
@@ -218,7 +246,7 @@ Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) cons
     if (aShape.IsNull()) return 0;
 
     aFunction->SetValue(aShape);
-    log.SetTouched(Label()); 
+    log->SetTouched(Label());
   } else if (aType == PROJECTION_ON_WIRE) {
     // Perform projection of point on a wire or an edge.
     GEOMImpl_IProjection aProj (aFunction);
@@ -386,6 +414,43 @@ Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) cons
     if (!hasValidSolution) {
       Standard_ConstructionError::Raise("Projection aborted : no projection");
     }
+  } else if (aType == PROJECTION_ON_CYLINDER) {
+    GEOMImpl_IProjOnCyl   aProj (aFunction);
+    Handle(GEOM_Function) aShapeFunction = aProj.GetShape();
+      
+    if (aShapeFunction.IsNull()) {
+      return 0;
+    }
+
+    TopoDS_Shape aShape = aShapeFunction->GetValue();
+
+    if (aShape.IsNull()) {
+      return 0;
+    }
+
+    // Get the face.
+    const TopAbs_ShapeEnum aType          = aShape.ShapeType();
+    const Standard_Real    aRadius        = aProj.GetRadius();
+    const Standard_Real    aStartAngle    = aProj.GetStartAngle();
+    const Standard_Real    aLengthAngle   = aProj.GetAngleLength();
+    const Standard_Real    aRotationAngle = aProj.GetAngleRotation();
+
+    if (aType != TopAbs_WIRE && aType != TopAbs_FACE) {
+      return 0;
+    }
+
+    if (aRadius <= Precision::Confusion()) {
+      return 0;
+    }
+
+    TopoDS_Shape aProjShape = projectOnCylinder
+      (aShape, aRadius, aStartAngle, aLengthAngle, aRotationAngle);
+
+    if (aProjShape.IsNull()) {
+      return 0;
+    }
+
+    aFunction->SetValue(aProjShape);
   }
 
   return 1;
@@ -410,28 +475,327 @@ GetCreationInformation(std::string&             theOperationName,
 
   switch ( aType ) {
   case PROJECTION_COPY:
-    {
-      GEOMImpl_IMirror aCI( function );
+  {
+    GEOMImpl_IMirror aCI( function );
 
-      AddParam( theParams, "Source object", aCI.GetOriginal() );
-      AddParam( theParams, "Target face", aCI.GetPlane() );
-      break;
-    }
+    AddParam( theParams, "Source object", aCI.GetOriginal() );
+    AddParam( theParams, "Target face", aCI.GetPlane() );
+    break;
+  }
   case PROJECTION_ON_WIRE:
-    {
-      GEOMImpl_IProjection aProj (function);
+  {
+    GEOMImpl_IProjection aProj (function);
+
+    AddParam(theParams, "Point", aProj.GetPoint());
+    AddParam(theParams, "Shape", aProj.GetShape());
+
+    break;
+  }
+  case PROJECTION_ON_CYLINDER:
+  {
+    theOperationName = "PROJ_ON_CYL";
+
+    GEOMImpl_IProjOnCyl aProj (function);
+    const Standard_Real aLengthAngle = aProj.GetAngleLength();
 
-      AddParam(theParams, "Point", aProj.GetPoint());
-      AddParam(theParams, "Shape", aProj.GetShape());
+    AddParam(theParams, "Shape",        aProj.GetShape());
+    AddParam(theParams, "Radius",       aProj.GetRadius());
+    AddParam(theParams, "Start angle",  aProj.GetStartAngle());
 
-      break;
+    if (aLengthAngle >= 0.) {
+      AddParam(theParams, "Length angle", aLengthAngle);
     }
+
+    AddParam(theParams, "Rotation angle", aProj.GetAngleRotation());
+
+    break;
+  }
   default:
     return false;
   }
-  
+
   return true;
 }
 
-IMPLEMENT_STANDARD_HANDLE (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);
+//================================================================================
+/*!
+ * \brief Performs projection of a planar wire or a face on a cylinder.
+ */
+//================================================================================
+
+TopoDS_Shape GEOMImpl_ProjectionDriver::projectOnCylinder
+                                (const TopoDS_Shape  &theShape,
+                                 const Standard_Real  theRadius,
+                                 const Standard_Real  theStartAngle,
+                                 const Standard_Real  theAngleLength,
+                                 const Standard_Real  theAngleRotation) const
+{
+  TopoDS_Shape aResult;
+
+  // Get the face.
+  const TopAbs_ShapeEnum aType = theShape.ShapeType();
+  TopoDS_Face            aFace;
+
+  if (aType == TopAbs_WIRE) {
+    // Try to create a planar face.
+    TopoDS_Wire             aWire = TopoDS::Wire(theShape);
+    BRepBuilderAPI_MakeFace aMkFace(aWire, Standard_True);
+
+    if (aMkFace.IsDone()) {
+      aFace = aMkFace.Face();
+    } else {
+      // Check if the wire is a straight line.
+      TopExp_Explorer anEExp(aWire, TopAbs_EDGE);
+      TopoDS_Edge     anEdge;
+
+      for (; anEExp.More(); anEExp.Next()) {
+        anEdge = TopoDS::Edge(anEExp.Current());
+
+        if (!BRep_Tool::Degenerated(anEdge)) {
+          break;
+        }
+      }
+
+      if (anEExp.More()) {
+        // Not degenerated edge found. Try to create a plane.
+        Standard_Real      aPar[2];
+        Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aPar[0], aPar[1]);
+        gp_Pnt             aP0    = aCurve->Value(aPar[0]);
+        gp_Pnt             aP1    = aCurve->Value(0.5*(aPar[1] + aPar[0]));
+        gp_Vec             aX(aP1.XYZ().Subtracted(aP0.XYZ()));
+        Standard_Real      aTolConf = Precision::Confusion();
+
+        if (aX.Magnitude() > aTolConf) {
+          aX.Normalize();
+
+          // Get the plane normal ortogonal to Z axis.
+          gp_Vec aZ(0., 0., 1.);
+          gp_Vec aN = aX.Crossed(aZ);
+
+          if (aN.Magnitude() <= aTolConf) {
+            // aX is parallel to aZ. Get the plane normal ortogonal to Y axis.
+            gp_Vec aY(0., 1., 0.);
+
+            aN = aX.Crossed(aY);
+          }
+
+          if (aN.Magnitude() >      aTolConf) {
+            gp_Ax3                  anAxis(aP0, gp_Dir(aN), gp_Dir(aX));
+            Handle(Geom_Plane)      aPlane = new Geom_Plane(anAxis);
+            BRepBuilderAPI_MakeFace aMkFace(aPlane, aWire);
+
+            if (aMkFace.IsDone()) {
+              aFace = aMkFace.Face();
+            }
+          }
+        }
+      }
+    }
+  } else if (aType == TopAbs_FACE) {
+    aFace = TopoDS::Face(theShape);
+  }
+
+  if (aFace.IsNull()) {
+    return aResult;
+  }
+
+  // Compute 2d translation transformation.
+  TopoDS_Wire            anOuterWire = BRepTools::OuterWire(aFace);
+  BRepTools_WireExplorer aOWExp(anOuterWire, aFace);
+
+  if (!aOWExp.More()) {
+    // NEVERREACHED
+    return aResult;
+  }
+
+  // Rotate 2D presentation of face.
+  TopoDS_Vertex       aFirstVertex = aOWExp.CurrentVertex();
+  TopoDS_Edge         aFirstEdge   = aOWExp.Current();
+  gp_Pnt              aPnt         = BRep_Tool::Pnt(aFirstVertex);
+  BRepAdaptor_Curve2d anAdaptorCurve(aFirstEdge, aFace);
+  Standard_Real       aParam       =
+    BRep_Tool::Parameter(aFirstVertex, aFirstEdge, aFace);
+  gp_Pnt2d            aPntUV;
+  gp_Vec2d            aVecUV;
+  gp_Vec2d            aVecU0(1., 0);
+
+  anAdaptorCurve.D1(aParam, aPntUV, aVecUV);
+
+  if (aVecUV.Magnitude() <= gp::Resolution()) {
+    return aResult;
+  }
+
+  if (aFirstEdge.Orientation() == TopAbs_REVERSED) {
+    aVecUV.Reverse();
+  }
+
+  const Standard_Real    anAngle    = aVecUV.Angle(aVecU0) + theAngleRotation;
+  const Standard_Boolean isToRotate = Abs(anAngle) > Precision::Angular();
+  gp_Trsf2d              aRotTrsf;
+  Bnd_Box2d              aUVBox;
+  Standard_Real          aPar[2];
+
+  if (isToRotate) {
+    aRotTrsf.SetRotation(aPntUV, anAngle);
+  }
+
+  for (; aOWExp.More(); aOWExp.Next()) {
+    TopoDS_Edge                 anEdge   = aOWExp.Current();
+    Handle(Geom2d_Curve)        aCurve   =
+        BRep_Tool::CurveOnSurface(anEdge, aFace, aPar[0], aPar[1]);
+
+    if (aCurve.IsNull()) {
+      continue;
+    }
+
+    if (isToRotate) {
+      aCurve = Handle(Geom2d_Curve)::DownCast(aCurve->Transformed(aRotTrsf));
+    }
+
+    BndLib_Add2dCurve::Add(aCurve, aPar[0], aPar[1], 0., aUVBox);
+  }
+
+  Standard_Real aU[2];
+  Standard_Real aV[2];
+
+  aUVBox.Get(aU[0], aV[0], aU[1], aV[1]);
+
+  // Compute anisotropic transformation from a face's 2d space
+  // to cylinder's 2d space.
+  GEOMUtils::Trsf2d aTrsf2d
+            (1./theRadius, 0., theStartAngle - aU[0]/theRadius,
+             0.,           1., aPnt.Z() - aPntUV.Y());
+
+  // Compute scaling trsf.
+  const Standard_Boolean isToScale = theAngleLength >= Precision::Angular();
+  gp_Trsf2d aScaleTrsf;
+
+  if (isToScale) {
+    // Perform 2d scaling.
+    gp_Pnt2d            aMidPnt(0.5*(aU[1] + aU[0]), 0.5*(aV[1] + aV[0]));
+    const Standard_Real aScaleFactor = theAngleLength*theRadius/(aU[1] - aU[0]);
+
+    aTrsf2d.TransformD0(aMidPnt);
+
+    aScaleTrsf.SetScale(aMidPnt, aScaleFactor);
+  }
+
+  // Get 2d presentation of a face.
+  Handle(Geom_Surface) aCylinder =
+    new Geom_CylindricalSurface(gp_Ax3(), theRadius);
+  GeomAdaptor_Surface  aGACyl(aCylinder);
+  TopExp_Explorer      anExp(aFace, TopAbs_WIRE);
+  TopTools_ListOfShape aWires;
+  Standard_Real        aUResol = aGACyl.UResolution(Precision::Confusion());
+  Standard_Real        aVResol = aGACyl.VResolution(Precision::Confusion());
+
+  for (; anExp.More(); anExp.Next()) {
+    TopoDS_Wire             aWire = TopoDS::Wire(anExp.Current());
+    BRepTools_WireExplorer  aWExp(aWire, aFace);
+    BRepBuilderAPI_MakeWire aMkWire;
+
+    for (; aWExp.More(); aWExp.Next()) {
+      TopoDS_Edge                 anEdge   = aWExp.Current();
+      Handle(Geom2d_Curve)        aCurve   =
+        BRep_Tool::CurveOnSurface(anEdge, aFace, aPar[0], aPar[1]);
+
+      if (aCurve.IsNull()) {
+        continue;
+      }
+
+      if (isToRotate) {
+        aCurve = Handle(Geom2d_Curve)::DownCast(aCurve->Transformed(aRotTrsf));
+      }
+
+      // Transform the curve to cylinder's parametric space.
+      Handle(GEOMUtils::HTrsfCurve2d) aTrsfCurve =
+        new GEOMUtils::HTrsfCurve2d(aCurve, aPar[0], aPar[1], aTrsf2d);
+      Approx_Curve2d                  aConv (aTrsfCurve, aPar[0], aPar[1],
+                                                         aUResol, aVResol, GeomAbs_C1,
+                                             9, 1000);
+
+      if (!aConv.IsDone() && !aConv.HasResult()) {
+        return aResult;
+      }
+
+      Handle(Geom2d_Curve) aCylCurve = aConv.Curve();
+
+      if (isToScale) {
+        aCylCurve->Transform(aScaleTrsf);
+      }
+
+      // Create edge and add it to the wire.
+      BRepBuilderAPI_MakeEdge aMkEdge(aCylCurve, aCylinder);
+
+      if (!aMkEdge.IsDone()) {
+        return aResult;
+      }
+
+      aMkWire.Add(aMkEdge.Edge());
+
+      if (!aMkWire.IsDone()) {
+        return aResult;
+      }
+    }
+
+    if (aWire.IsSame(anOuterWire)) {
+      // Make the outer wire first.
+      aWires.Prepend(aMkWire.Wire());
+    } else {
+      aWires.Append(aMkWire.Wire());
+    }
+  }
+
+  // Create a face.
+  if (aWires.IsEmpty()) {
+    return aResult;
+  }
+
+  TopTools_ListIteratorOfListOfShape aWIter(aWires);
+  TopoDS_Wire                        aWire = TopoDS::Wire(aWIter.Value());
+  BRepBuilderAPI_MakeFace aMkFace(aCylinder, aWire);
+
+  if (!aMkFace.IsDone()) {
+    return aResult;
+  }
+
+  for (aWIter.Next(); aWIter.More(); aWIter.Next()) {
+    aWire = TopoDS::Wire(aWIter.Value());
+    aMkFace.Add(aWire);
+
+    if (!aMkFace.IsDone()) {
+      return aResult;
+    }
+  }
+
+  // Build 3D curves.
+  TopoDS_Face  aCylFace = aMkFace.Face();
+  TopoDS_Shape aResShape;
+
+  BRepLib::BuildCurves3d(aCylFace);
+
+  // Check shape.
+  if (aType == TopAbs_WIRE) {
+    TopExp_Explorer aResExp(aCylFace, TopAbs_WIRE);
+
+    if (aResExp.More()) {
+      aResShape = aResExp.Current();
+    }
+  } else {
+    aResShape = aCylFace;
+  }
+
+  if (aResShape.IsNull() == Standard_False) {
+    if (!GEOMUtils::CheckShape(aResShape, true)) {
+      if (!GEOMUtils::FixShapeTolerance(aResShape)) {
+        return aResult;
+      }
+    }
+
+    aResult = aResShape;
+  }
+
+  return aResult;
+}
+
 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);