Salome HOME
Issue #2068: change of arc is by jump even due to smooth mouse movement
authorazv <azv@opencascade.com>
Mon, 3 Apr 2017 09:45:17 +0000 (12:45 +0300)
committerazv <azv@opencascade.com>
Mon, 3 Apr 2017 09:53:53 +0000 (12:53 +0300)
Improve building of tangent arc by taking into account a point, selected by user.

src/GeomAPI/GeomAPI_Circ2d.cpp
src/GeomAPI/GeomAPI_Circ2d.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Fillet.cpp
src/SketchPlugin/SketchPlugin_MacroArc.cpp
src/SketchPlugin/SketchPlugin_MacroCircle.cpp

index 9061473b0cc0576dbd6e9468a20ea444736167d0..7cb9f20ba2fdb02df4fb556aa8af1b27e040e562 100644 (file)
 // Author:      Artem ZHIDKOV
 
 #include <GeomAPI_Circ2d.h>
-#include <GeomAPI_Ax3.h>
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Shape.h>
 
-#include <BRep_Tool.hxx>
-#include <ElCLib.hxx>
-#include <gp_Dir2d.hxx>
 #include <gp_Circ2d.hxx>
-#include <gp_Lin2d.hxx>
 #include <gp_Pnt2d.hxx>
-#include <gp_Ax2d.hxx>
-#include <GccAna_Circ2d2TanRad.hxx>
-#include <GccAna_Circ2d3Tan.hxx>
-#include <GccAna_Circ2dTanCen.hxx>
-#include <GccEnt.hxx>
-#include <GccEnt_QualifiedCirc.hxx>
-#include <GccEnt_QualifiedLin.hxx>
 #include <GeomLib_Tool.hxx>
 #include <Geom2d_Circle.hxx>
-#include <Geom2dAPI_ProjectPointOnCurve.hxx>
-#include <Geom_Plane.hxx>
-#include <IntAna2d_AnaIntersection.hxx>
 #include <Precision.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Edge.hxx>
-
-#include <vector>
 
 #define MY_CIRC2D implPtr<gp_Circ2d>()
 
-typedef std::shared_ptr<Geom2dAdaptor_Curve>  CurveAdaptorPtr;
-typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
-typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> >  VectorOfGccLine;
-
-// Provide different mechanisms to create circle:
-// * by passing points
-// * by tangent edges
-// * with specified radius
-// * etc.
-class CircleBuilder
-{
-public:
-  CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
-    : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
-      myRadius(0.0)
-  {}
-
-  void setRadius(const double theRadius)
-  { myRadius = theRadius; }
-
-  void addCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
-  { myCenter = theCenter; }
-
-  void addPassingEntity(const std::shared_ptr<GeomAPI_Interface>& theEntity)
-  {
-    std::shared_ptr<GeomAPI_Pnt2d> aPoint = std::dynamic_pointer_cast<GeomAPI_Pnt2d>(theEntity);
-    if (aPoint)
-      addPassingPoint(aPoint);
-    else {
-      std::shared_ptr<GeomAPI_Shape> aShape = std::dynamic_pointer_cast<GeomAPI_Shape>(theEntity);
-      if (aShape)
-        addTangentCurve(aShape);
-    }
-  }
-
-  void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
-  {
-    if (!theEdge->isEdge())
-      return;
-
-    const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
-
-    double aFirst, aLast;
-    TopLoc_Location aLoc;
-    Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
-    CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
-
-    myTangentShapes.push_back(aCurveAdaptor);
-  }
-
-  void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-  {
-    myPassingPoints.push_back(thePoint->impl<gp_Pnt2d>());
-  }
-
-  gp_Circ2d* circle()
-  {
-    if (myTangentShapes.size() > 1)
-      sortTangentShapes();
-
-    gp_Circ2d* aResult = 0;
-    if (myCenter) {
-      if (myPassingPoints.size() == 1)
-        aResult = circleByCenterAndPassingPoint();
-      else if (myTangentShapes.size() == 1)
-        aResult = circleByCenterAndTangent();
-      else if (myRadius > 0.0)
-        aResult = circleByCenterAndRadius();
-    } else if (myRadius > 0.0) {
-      if (myTangentShapes.size() == 2)
-        aResult = circleByRadiusAndTwoTangentCurves();
-    } else {
-      switch (myPassingPoints.size()) {
-      case 0:
-        aResult = circleByThreeTangentCurves();
-        break;
-      case 1:
-        aResult = circleByPointAndTwoTangentCurves();
-        break;
-      case 2:
-        aResult = circleByTwoPointsAndTangentCurve();
-        break;
-      case 3:
-        aResult = circleByThreePassingPoints();
-        break;
-      default:
-        break;
-      }
-    }
-    return aResult;
-  }
-
-private:
-  void sortTangentShapes()
-  {
-    // sort tangent shapes, so circles go before lines
-    int aSize = (int)myTangentShapes.size();
-    for (int i = 1; i < aSize; ++i) {
-      if (myTangentShapes[i]->GetType() != GeomAbs_Circle)
-        continue;
-
-      for (int j = i - 1; j >= 0 && myTangentShapes[j]->GetType() == GeomAbs_Line; --j)
-        std::swap(myTangentShapes[j], myTangentShapes[j+1]);
-    }
-  }
-
-  gp_Circ2d* circleByCenterAndRadius()
-  {
-    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
-    return new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius);
-  }
-
-  gp_Circ2d* circleByCenterAndPassingPoint()
-  {
-    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
-    GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
-    if (aBuilder.NbSolutions() > 0)
-      return new gp_Circ2d(aBuilder.ThisSolution(1));
-    return 0;
-  }
-
-  gp_Circ2d* circleByCenterAndTangent()
-  {
-    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
-    CurveAdaptorPtr aCurve = myTangentShapes[0];
-
-    std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
-    if (aCurve->GetType() == GeomAbs_Line) {
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
-          new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
-    } else if (aCurve->GetType() == GeomAbs_Circle) {
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
-          GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
-    }
-
-    return getProperCircle(aCircleBuilder);
-  }
-
-  gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
-  {
-    if (!theBuilder)
-      return 0;
-
-    CurveAdaptorPtr aCurve = myTangentShapes[0];
-
-    gp_Circ2d* aResult = 0;
-    int aNbSol = theBuilder->NbSolutions();
-    double aParSol, aPonTgCurve;
-    gp_Pnt2d aTgPnt;
-    for (int i = 1; i <= aNbSol && aCurve; ++i) {
-      theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
-      if (isParamOnCurve(aPonTgCurve, aCurve)) {
-        aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
-        break;
-      }
-    }
-    // unable to build circle passing through the tangent curve,
-    // so get a circle passing any tangent point
-    if (!aResult && aNbSol > 0)
-      aResult =  new gp_Circ2d(theBuilder->ThisSolution(1));
-    return aResult;
-  }
-
-
-  gp_Circ2d* circleByThreeTangentCurves()
-  {
-    VectorOfGccCirc aTgCirc;
-    VectorOfGccLine aTgLine;
-    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
-
-    if (aTgCirc.size() + aTgLine.size() != 3)
-      return 0;
-
-    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
-    switch (aTgLine.size()) {
-    case 0:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-          *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
-      break;
-    case 1:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-          *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
-      break;
-    case 2:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-          *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
-      break;
-    case 3:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-          *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
-      break;
-    default:
-      break;
-    }
-
-    return getProperCircle(aCircleBuilder);
-  }
-
-  gp_Circ2d* circleByPointAndTwoTangentCurves()
-  {
-    const gp_Pnt2d& aPoint = myPassingPoints[0];
-    CurveAdaptorPtr aCurve1 = myTangentShapes[0];
-    CurveAdaptorPtr aCurve2 = myTangentShapes[1];
-    if (!aCurve1 || !aCurve2)
-      return 0;
-
-    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
-    if (aCurve1->GetType() == GeomAbs_Line) {
-      if (aCurve2->GetType() == GeomAbs_Line) {
-        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
-            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
-                                  GccEnt::Unqualified(aCurve2->Line()),
-                                  aPoint, Precision::Confusion()));
-      } else if (aCurve2->GetType() == GeomAbs_Circle) {
-        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
-            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
-                                  GccEnt::Unqualified(aCurve1->Line()),
-                                  aPoint, Precision::Confusion()));
-      }
-    } else if (aCurve1->GetType() == GeomAbs_Circle) {
-      if (aCurve2->GetType() == GeomAbs_Line) {
-        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
-            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
-                                  GccEnt::Unqualified(aCurve2->Line()),
-                                  aPoint, Precision::Confusion()));
-      } else if (aCurve2->GetType() == GeomAbs_Circle) {
-        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
-            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
-                                  GccEnt::Unqualified(aCurve1->Circle()),
-                                  aPoint, Precision::Confusion()));
-      }
-    }
-
-    return getProperCircle(aCircleBuilder);
-  }
-
-  gp_Circ2d* circleByTwoPointsAndTangentCurve()
-  {
-    const gp_Pnt2d& aPoint1 = myPassingPoints[0];
-    const gp_Pnt2d& aPoint2 = myPassingPoints[1];
-    CurveAdaptorPtr aCurve = myTangentShapes[0];
-    if (!aCurve)
-      return 0;
-
-    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
-    if (aCurve->GetType() == GeomAbs_Line) {
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-        GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
-    } else if (aCurve->GetType() == GeomAbs_Circle) {
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
-          GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
-    }
-
-    return getProperCircle(aCircleBuilder);
-  }
-
-  gp_Circ2d* circleByThreePassingPoints()
-  {
-    GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
-                                     myPassingPoints[1],
-                                     myPassingPoints[2],
-                                     Precision::Confusion());
-    if (aCircleBuilder.NbSolutions() > 0)
-      return new gp_Circ2d(aCircleBuilder.ThisSolution(1));
-    return 0;
-  }
-
-  gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
-  {
-    if (!theBuilder)
-      return 0;
-
-    gp_Circ2d* aResult = 0;
-    int aNbSol = theBuilder->NbSolutions();
-    double aParSol, aPonTgCurve;
-    gp_Pnt2d aTgPnt;
-    for (int i = 1; i <= aNbSol; ++i) {
-      bool isApplicable = false;
-      if (myTangentShapes.size() >= 1) {
-        theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
-        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
-      }
-      if (myTangentShapes.size() >= 2 && isApplicable) {
-        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
-        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
-      }
-      if (myTangentShapes.size() >= 3 && isApplicable) {
-        theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
-        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
-      }
-
-      if (isApplicable) {
-        aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
-        break;
-      }
-    }
-    // unable to build circle passing through the tangent curve => get any tangent point
-    if (!aResult && aNbSol > 0)
-      aResult =  new gp_Circ2d(theBuilder->ThisSolution(1));
-    return aResult;
-  }
-
-
-  gp_Circ2d* circleByRadiusAndTwoTangentCurves()
-  {
-    VectorOfGccCirc aTgCirc;
-    VectorOfGccLine aTgLine;
-    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
-
-    if (aTgCirc.size() + aTgLine.size() != 2)
-      return 0;
-
-    std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
-    switch (aTgLine.size()) {
-    case 0:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
-          *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
-      break;
-    case 1:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
-          *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
-      break;
-    case 2:
-      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
-          *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
-      break;
-    default:
-      break;
-    }
-
-    return getProperCircle(aCircleBuilder);
-  }
-
-  gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
-  {
-    if (!theBuilder)
-      return 0;
-
-    gp_Circ2d* aResult = 0;
-    int aNbSol = theBuilder->NbSolutions();
-    double aParSol, aPonTgCurve;
-    gp_Pnt2d aTgPnt;
-    for (int i = 1; i <= aNbSol; ++i) {
-      bool isApplicable = false;
-      if (myTangentShapes.size() >= 1) {
-        theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
-        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
-      }
-      if (myTangentShapes.size() >= 2 && isApplicable) {
-        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
-        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
-      }
-
-      if (isApplicable) {
-        aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
-        break;
-      }
-    }
-    // unable to build circle passing through the tangent curve => get any tangent point
-    if (!aResult && aNbSol > 0)
-      aResult =  new gp_Circ2d(theBuilder->ThisSolution(1));
-    return aResult;
-  }
-
-
-  void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
-                                    VectorOfGccLine& theTangentLines)
-  {
-    theTangentCircles.reserve(3);
-    theTangentLines.reserve(3);
-
-    std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
-    for (; anIt != myTangentShapes.end(); ++anIt) {
-      switch ((*anIt)->GetType()) {
-      case GeomAbs_Line:
-        theTangentLines.push_back(
-            std::shared_ptr<GccEnt_QualifiedLin>(
-            new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
-        );
-        break;
-      case GeomAbs_Circle:
-        theTangentCircles.push_back(
-            std::shared_ptr<GccEnt_QualifiedCirc>(
-            new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
-        );
-        break;
-      default:
-        break;
-      }
-    }
-  }
-
-
-  // boundary parameters of curve are NOT applied
-  static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
-  {
-    if (theCurve->Curve()->IsPeriodic()) {
-      theParameter = ElCLib::InPeriod(theParameter,
-                                      theCurve->FirstParameter(),
-                                      theCurve->FirstParameter() + theCurve->Period());
-    }
-    return theParameter > theCurve->FirstParameter() &&
-           theParameter < theCurve->LastParameter();
-  }
-
-  // boundary parameters of curve are applied too
-  static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
-  {
-    if (theCurve->IsPeriodic()) {
-      theParameter = ElCLib::InPeriod(theParameter,
-                                      theCurve->FirstParameter(),
-                                      theCurve->FirstParameter() + theCurve->Period());
-    }
-    return theParameter >= theCurve->FirstParameter() &&
-           theParameter <= theCurve->LastParameter();
-  }
-
-private:
-  Handle(Geom_Plane) myPlane;
-  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
-  std::vector<gp_Pnt2d> myPassingPoints;
-  std::vector<CurveAdaptorPtr> myTangentShapes;
-  double myRadius;
-};
-
-typedef std::shared_ptr<CircleBuilder> CircleBuilderPtr;
-
 
 static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, const gp_Dir2d theDir,
                             const double theRadius)
@@ -487,49 +40,6 @@ static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY,
   return newCirc2d(theCenterX, theCenterY, aDir, aRadius);
 }
 
-static gp_Circ2d* newCirc2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                            const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
-                            const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
-{
-  gp_XY aFirstPnt(theFirstPoint->x(), theFirstPoint->y());
-  gp_XY aSecondPnt(theSecondPoint->x(), theSecondPoint->y());
-  gp_XY aThirdPnt(theThirdPoint->x(), theThirdPoint->y());
-
-  gp_XY aVec12 = aSecondPnt - aFirstPnt;
-  gp_XY aVec23 = aThirdPnt - aSecondPnt;
-  gp_XY aVec31 = aFirstPnt - aThirdPnt;
-
-  // coefficients to calculate center
-  double aCoeff1, aCoeff2, aCoeff3;
-
-  // square of parallelogram
-  double aSquare2 = aVec12.Crossed(aVec23);
-  aSquare2 *= aSquare2 * 2.0;
-  if (aSquare2 < 1.e-20) {
-    // if two points are equal, build a circle on two different points as on diameter
-    double aSqLen12 = aVec12.SquareModulus();
-    double aSqLen23 = aVec23.SquareModulus();
-    double aSqLen31 = aVec31.SquareModulus();
-    if (aSqLen12 < Precision::SquareConfusion() &&
-        aSqLen23 < Precision::SquareConfusion() &&
-        aSqLen31 < Precision::SquareConfusion())
-      return NULL;
-    aCoeff1 = aCoeff2 = aCoeff3 = 1.0 / 3.0;
-  }
-  else {
-    aCoeff1 = aVec23.Dot(aVec23) / aSquare2 * aVec12.Dot(aVec31.Reversed());
-    aCoeff2 = aVec31.Dot(aVec31) / aSquare2 * aVec23.Dot(aVec12.Reversed());
-    aCoeff3 = aVec12.Dot(aVec12) / aSquare2 * aVec31.Dot(aVec23.Reversed());
-  }
-  // center
-  gp_XY aCenter = aFirstPnt * aCoeff1 + aSecondPnt * aCoeff2 + aThirdPnt * aCoeff3;
-  // radius
-  double aRadius = (aFirstPnt - aCenter).Modulus();
-
-  gp_Dir2d aDir(aFirstPnt - aCenter);
-  return newCirc2d(aCenter.X(), aCenter.Y(), aDir, aRadius);
-}
-
 
 
 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
@@ -546,49 +56,6 @@ GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
 {
 }
 
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
-    : GeomAPI_Interface(newCirc2d(theFirstPoint, theSecondPoint, theThirdPoint))
-{
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-                               const std::shared_ptr<GeomAPI_Shape>& theTangent,
-                               const std::shared_ptr<GeomAPI_Ax3>&   thePlane)
-{
-  CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
-  aBuilder->addCenter(theCenter);
-  aBuilder->addTangentCurve(theTangent);
-  setImpl(aBuilder->circle());
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
-                               const std::shared_ptr<GeomAPI_Interface>& theEntity2,
-                               const std::shared_ptr<GeomAPI_Interface>& theEntity3,
-                               const std::shared_ptr<GeomAPI_Ax3>&       thePlane)
-{
-  CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
-  aBuilder->addPassingEntity(theEntity1);
-  aBuilder->addPassingEntity(theEntity2);
-  aBuilder->addPassingEntity(theEntity3);
-  setImpl(aBuilder->circle());
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
-                               const std::shared_ptr<GeomAPI_Interface>& theEntity2,
-                               const double                              theRadius,
-                               const std::shared_ptr<GeomAPI_Ax3>&       thePlane)
-{
-  CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
-  aBuilder->addPassingEntity(theEntity1);
-  aBuilder->addPassingEntity(theEntity2);
-  aBuilder->setRadius(theRadius);
-  setImpl(aBuilder->circle());
-}
-
-
-
 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
     const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
 {
index 427197a84060e1edec54394488b666450c0b04da..42e47defaba1018dcc460823afbae2dd476b5ac7 100644 (file)
@@ -33,34 +33,6 @@ class GeomAPI_Circ2d : public GeomAPI_Interface
   GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
                  const std::shared_ptr<GeomAPI_Dir2d>& theDir, double theRadius);
 
-  /// Creation of circle defined by three points lying on it
-  GEOMAPI_EXPORT
-  GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
-                 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint);
-
-  /// Creation of a circle defined by center and a tangent curve on the given plane
-  GEOMAPI_EXPORT
-  GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-                 const std::shared_ptr<GeomAPI_Shape>& theTangent,
-                 const std::shared_ptr<GeomAPI_Ax3>&   thePlane);
-
-  /// Creation of a circle passing through or tangent to given entities.
-  /// Supported items are GeomAPI_Pnt2d or GeomAPI_Shape
-  GEOMAPI_EXPORT
-  GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
-                 const std::shared_ptr<GeomAPI_Interface>& theEntity2,
-                 const std::shared_ptr<GeomAPI_Interface>& theEntity3,
-                 const std::shared_ptr<GeomAPI_Ax3>&       thePlane);
-
-  /// Creation of a circle with given radius passing through or tangent to two entities.
-  /// Supported items are GeomAPI_Pnt2d or GeomAPI_Shape
-  GEOMAPI_EXPORT
-  GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
-                 const std::shared_ptr<GeomAPI_Interface>& theEntity2,
-                 const double                              theRadius,
-                 const std::shared_ptr<GeomAPI_Ax3>&       thePlane);
-
   /// Return center of the circle
   GEOMAPI_EXPORT
   const std::shared_ptr<GeomAPI_Pnt2d> center() const;
index 2b5d6a2c6089ffab441f6356c7cf69fa8dc5b9ae..920d67d6d555943da018f355661b6f44bc5c0d4d 100644 (file)
@@ -49,6 +49,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_ConeSegment.h
     GeomAlgoAPI_Symmetry.h
     GeomAlgoAPI_Scale.h
+    GeomAlgoAPI_Circ2dBuilder.h
 )
 
 SET(PROJECT_SOURCES
@@ -94,6 +95,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_ConeSegment.cpp
     GeomAlgoAPI_Symmetry.cpp
     GeomAlgoAPI_Scale.cpp
+    GeomAlgoAPI_Circ2dBuilder.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp
new file mode 100644 (file)
index 0000000..793ec3f
--- /dev/null
@@ -0,0 +1,537 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File:        GeomAlgoAPI_Circ2dBuilder.cpp
+// Created:     3 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <GeomAlgoAPI_Circ2dBuilder.h>
+#include <GeomAPI_Ax3.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Shape.h>
+
+#include <BRep_Tool.hxx>
+#include <ElCLib.hxx>
+#include <GccAna_Circ2d2TanRad.hxx>
+#include <GccAna_Circ2d3Tan.hxx>
+#include <GccAna_Circ2dTanCen.hxx>
+#include <GccEnt.hxx>
+#include <GccEnt_QualifiedCirc.hxx>
+#include <GccEnt_QualifiedLin.hxx>
+#include <Geom2dAdaptor_Curve.hxx>
+#include <Geom_Plane.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+
+#include <cmath>
+
+typedef std::shared_ptr<gp_Circ2d> Circ2dPtr;
+typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
+typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
+typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> >  VectorOfGccLine;
+
+
+// Provide different mechanisms to create circle:
+// * by passing points
+// * by tangent edges
+// * with specified radius
+// * etc.
+class CircleBuilder
+{
+public:
+  CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
+    : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
+      myRadius(0.0)
+  {}
+
+  void setRadius(const double theRadius)
+  { myRadius = theRadius; }
+
+  void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
+  { myCenter = theCenter; }
+
+  void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
+  {
+    std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
+    for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
+      const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl<TopoDS_Shape>());
+
+      double aFirst, aLast;
+      TopLoc_Location aLoc;
+      Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
+      CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
+
+      // sort curves (circles should become first)
+      if (aCurveAdaptor->GetType() == GeomAbs_Circle)
+        myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
+      else
+        myTangentShapes.push_back(aCurveAdaptor);
+    }
+  }
+
+  void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
+  {
+    std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
+    for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
+      myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
+  }
+
+  void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+  { myClosestPoint = thePoint; }
+
+
+  Circ2dPtr circle()
+  {
+    Circ2dPtr aResult;
+    if (myCenter) {
+      if (myPassingPoints.size() == 1)
+        aResult = circleByCenterAndPassingPoint();
+      else if (myTangentShapes.size() == 1)
+        aResult = circleByCenterAndTangent();
+      else if (myRadius > 0.0)
+        aResult = circleByCenterAndRadius();
+    } else if (myRadius > 0.0) {
+      if (myTangentShapes.size() == 2)
+        aResult = circleByRadiusAndTwoTangentCurves();
+    } else {
+      switch (myPassingPoints.size()) {
+      case 0:
+        aResult = circleByThreeTangentCurves();
+        break;
+      case 1:
+        aResult = circleByPointAndTwoTangentCurves();
+        break;
+      case 2:
+        aResult = circleByTwoPointsAndTangentCurve();
+        break;
+      case 3:
+        aResult = circleByThreePassingPoints();
+        break;
+      default:
+        break;
+      }
+    }
+    return aResult;
+  }
+
+private:
+  Circ2dPtr circleByCenterAndRadius()
+  {
+    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+    return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
+  }
+
+  Circ2dPtr circleByCenterAndPassingPoint()
+  {
+    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+    GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
+    if (aBuilder.NbSolutions() > 0)
+      return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
+    return Circ2dPtr();
+  }
+
+  Circ2dPtr circleByCenterAndTangent()
+  {
+    const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+    CurveAdaptorPtr aCurve = myTangentShapes[0];
+
+    std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
+    if (aCurve->GetType() == GeomAbs_Line) {
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
+          new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
+    } else if (aCurve->GetType() == GeomAbs_Circle) {
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
+          GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
+  {
+    if (!theBuilder)
+      return Circ2dPtr();
+
+    CurveAdaptorPtr aCurve = myTangentShapes[0];
+
+    int aNbSol = theBuilder->NbSolutions();
+    if (aNbSol == 0)
+      return Circ2dPtr();
+
+    int anAppropriateSolution = 1;
+    double aMinDist = Precision::Infinite();
+
+    double aParSol, aPonTgCurve;
+    gp_Pnt2d aTgPnt;
+    for (int i = 1; i <= aNbSol && aCurve; ++i) {
+      theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
+      if (isParamOnCurve(aPonTgCurve, aCurve)) {
+        double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+        if (aDist < aMinDist) {
+          anAppropriateSolution = i;
+          aMinDist = aDist;
+        }
+      }
+    }
+
+    return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+  }
+
+  double distanceToClosestPoint(const gp_Circ2d& theCirc) const
+  {
+    if (myClosestPoint) {
+      double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
+      return fabs(aDist - theCirc.Radius());
+    }
+    return 0.0;
+  }
+
+
+  Circ2dPtr circleByThreeTangentCurves()
+  {
+    VectorOfGccCirc aTgCirc;
+    VectorOfGccLine aTgLine;
+    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
+
+    if (aTgCirc.size() + aTgLine.size() != 3)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
+    switch (aTgLine.size()) {
+    case 0:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+          *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
+      break;
+    case 1:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+          *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
+      break;
+    case 2:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+          *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
+      break;
+    case 3:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+          *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
+      break;
+    default:
+      break;
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  Circ2dPtr circleByPointAndTwoTangentCurves()
+  {
+    const gp_Pnt2d& aPoint = myPassingPoints[0];
+    CurveAdaptorPtr aCurve1 = myTangentShapes[0];
+    CurveAdaptorPtr aCurve2 = myTangentShapes[1];
+    if (!aCurve1 || !aCurve2)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
+    if (aCurve1->GetType() == GeomAbs_Line) {
+      if (aCurve2->GetType() == GeomAbs_Line) {
+        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
+            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
+                                  GccEnt::Unqualified(aCurve2->Line()),
+                                  aPoint, Precision::Confusion()));
+      } else if (aCurve2->GetType() == GeomAbs_Circle) {
+        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
+            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
+                                  GccEnt::Unqualified(aCurve1->Line()),
+                                  aPoint, Precision::Confusion()));
+      }
+    } else if (aCurve1->GetType() == GeomAbs_Circle) {
+      if (aCurve2->GetType() == GeomAbs_Line) {
+        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
+            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
+                                  GccEnt::Unqualified(aCurve2->Line()),
+                                  aPoint, Precision::Confusion()));
+      } else if (aCurve2->GetType() == GeomAbs_Circle) {
+        aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
+            new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
+                                  GccEnt::Unqualified(aCurve1->Circle()),
+                                  aPoint, Precision::Confusion()));
+      }
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  Circ2dPtr circleByTwoPointsAndTangentCurve()
+  {
+    const gp_Pnt2d& aPoint1 = myPassingPoints[0];
+    const gp_Pnt2d& aPoint2 = myPassingPoints[1];
+    CurveAdaptorPtr aCurve = myTangentShapes[0];
+    if (!aCurve)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
+    if (aCurve->GetType() == GeomAbs_Line) {
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+        GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
+    } else if (aCurve->GetType() == GeomAbs_Circle) {
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
+          GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  Circ2dPtr circleByThreePassingPoints()
+  {
+    GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
+                                     myPassingPoints[1],
+                                     myPassingPoints[2],
+                                     Precision::Confusion());
+    if (aCircleBuilder.NbSolutions() > 0)
+      return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
+    return Circ2dPtr();
+  }
+
+  Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
+  {
+    if (!theBuilder)
+      return Circ2dPtr();
+
+    int aNbSol = theBuilder->NbSolutions();
+    if (aNbSol == 0)
+      return Circ2dPtr();
+
+    int anAppropriateSolution = 1;
+    double aMinDist = Precision::Infinite();
+
+    double aParSol, aPonTgCurve;
+    gp_Pnt2d aTgPnt;
+    for (int i = 1; i <= aNbSol; ++i) {
+      bool isApplicable = false;
+      if (myTangentShapes.size() >= 1) {
+        theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
+      }
+      if (myTangentShapes.size() >= 2 && isApplicable) {
+        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
+      }
+      if (myTangentShapes.size() >= 3 && isApplicable) {
+        theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
+      }
+
+      if (isApplicable) {
+        double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+        if (aDist < aMinDist) {
+          anAppropriateSolution = i;
+          aMinDist = aDist;
+        }
+      }
+    }
+
+    return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+  }
+
+
+  Circ2dPtr circleByRadiusAndTwoTangentCurves()
+  {
+    VectorOfGccCirc aTgCirc;
+    VectorOfGccLine aTgLine;
+    convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
+
+    if (aTgCirc.size() + aTgLine.size() != 2)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
+    switch (aTgLine.size()) {
+    case 0:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
+      break;
+    case 1:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
+      break;
+    case 2:
+      aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
+          *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
+      break;
+    default:
+      break;
+    }
+
+    return getProperCircle(aCircleBuilder);
+  }
+
+  Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
+  {
+    if (!theBuilder)
+      return Circ2dPtr();
+
+    int aNbSol = theBuilder->NbSolutions();
+    if (aNbSol == 0)
+      return Circ2dPtr();
+
+    int anAppropriateSolution = 1;
+    double aMinDist = Precision::Infinite();
+
+    double aParSol, aPonTgCurve;
+    gp_Pnt2d aTgPnt;
+    for (int i = 1; i <= aNbSol; ++i) {
+      bool isApplicable = false;
+      if (myTangentShapes.size() >= 1) {
+        theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
+      }
+      if (myTangentShapes.size() >= 2 && isApplicable) {
+        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
+      }
+
+      if (isApplicable) {
+        double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+        if (aDist < aMinDist) {
+          anAppropriateSolution = i;
+          aMinDist = aDist;
+        }
+      }
+    }
+
+    return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+  }
+
+
+  void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
+                                    VectorOfGccLine& theTangentLines)
+  {
+    theTangentCircles.reserve(3);
+    theTangentLines.reserve(3);
+
+    std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
+    for (; anIt != myTangentShapes.end(); ++anIt) {
+      switch ((*anIt)->GetType()) {
+      case GeomAbs_Line:
+        theTangentLines.push_back(
+            std::shared_ptr<GccEnt_QualifiedLin>(
+            new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
+        );
+        break;
+      case GeomAbs_Circle:
+        theTangentCircles.push_back(
+            std::shared_ptr<GccEnt_QualifiedCirc>(
+            new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
+        );
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+
+  // boundary parameters of curve are NOT applied
+  static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
+  {
+    if (theCurve->Curve()->IsPeriodic()) {
+      theParameter = ElCLib::InPeriod(theParameter,
+                                      theCurve->FirstParameter(),
+                                      theCurve->FirstParameter() + theCurve->Period());
+    }
+    return theParameter > theCurve->FirstParameter() &&
+           theParameter < theCurve->LastParameter();
+  }
+
+  // boundary parameters of curve are applied too
+  static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
+  {
+    if (theCurve->IsPeriodic()) {
+      theParameter = ElCLib::InPeriod(theParameter,
+                                      theCurve->FirstParameter(),
+                                      theCurve->FirstParameter() + theCurve->Period());
+    }
+    return theParameter >= theCurve->FirstParameter() &&
+           theParameter <= theCurve->LastParameter();
+  }
+
+private:
+  Handle(Geom_Plane) myPlane;
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::vector<gp_Pnt2d> myPassingPoints;
+  std::vector<CurveAdaptorPtr> myTangentShapes;
+  double myRadius;
+  std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
+};
+
+
+
+
+
+GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
+  : myPlane(thePlane),
+    myRadius(0.)
+{
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
+{
+  myRadius = theRadius;
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
+{
+  myCenter = theCenter;
+}
+
+void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
+{
+  if (theEdge->isEdge())
+    myTangentShapes.push_back(theEdge);
+}
+
+void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+  myPassingPoints.push_back(thePoint);
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+  myClosestPoint = thePoint;
+}
+
+std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
+{
+  std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
+
+  GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
+  aBuilder.addPassingPoint(theFirstPoint);
+  aBuilder.addPassingPoint(theSecondPoint);
+  aBuilder.addPassingPoint(theThirdPoint);
+  return aBuilder.circle();
+}
+
+std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
+{
+  CircleBuilder aCircleBuilder(myPlane);
+  aCircleBuilder.setCenter(myCenter);
+  aCircleBuilder.setTangentCurves(myTangentShapes);
+  aCircleBuilder.setPassingPoints(myPassingPoints);
+  aCircleBuilder.setClosestPoint(myClosestPoint);
+  aCircleBuilder.setRadius(myRadius);
+  Circ2dPtr aCirc2d = aCircleBuilder.circle();
+
+  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  if (aCirc2d) {
+    const gp_Pnt2d& aCenter = aCirc2d->Location();
+    const gp_Dir2d& aXAxis = aCirc2d->XAxis().Direction();
+
+    std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
+    std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
+
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(
+        new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));
+  }
+  return aCircle;
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h
new file mode 100644 (file)
index 0000000..6aad612
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File:        GeomAlgoAPI_Circ2dBuilder.h
+// Created:     3 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef GeomAlgoAPI_Circ2dBuilder_H_
+#define GeomAlgoAPI_Circ2dBuilder_H_
+
+#include <GeomAlgoAPI.h>
+
+#include <memory>
+#include <vector>
+
+class GeomAPI_Ax3;
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
+
+/// \class GeomAlgoAPI_Circ2dBuilder
+/// \ingroup DataAlgo
+/// \brief Creates circle in 2D space satisfying combination of the following constraints:
+///        * center of a circle
+///        * passing through the point
+///        * tangent to a curve
+///        * fixed radius
+class GeomAlgoAPI_Circ2dBuilder
+{
+public:
+  /// \brief Create a builder object.
+  ///        Constraints should be applied separately.
+  /// \param thePlane [in]  plane to project tangent curves
+  GEOMALGOAPI_EXPORT
+  GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane);
+
+  /// \brief Set fixed radius of the circle
+  GEOMALGOAPI_EXPORT
+  void setRadius(const double theRadius);
+
+  /// \brief Set fixed center of the circle
+  GEOMALGOAPI_EXPORT
+  void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter);
+
+  /// \brief Constrain circle to be tangent to the given edge
+  GEOMALGOAPI_EXPORT
+  void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+
+  /// \brief Constrain circle to pass through the given point
+  GEOMALGOAPI_EXPORT
+  void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+  /// \brief Optional constraint to find circle closest to the given point
+  GEOMALGOAPI_EXPORT
+  void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+  /// \brief Build circle
+  GEOMALGOAPI_EXPORT
+  std::shared_ptr<GeomAPI_Circ2d> circle();
+
+  /// \brief Create a circle passing through three points
+  GEOMALGOAPI_EXPORT
+  static std::shared_ptr<GeomAPI_Circ2d>
+      circle(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+             const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
+             const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint);
+
+private:
+  std::shared_ptr<GeomAPI_Ax3>                  myPlane;
+  std::shared_ptr<GeomAPI_Pnt2d>                myCenter;
+  std::vector< std::shared_ptr<GeomAPI_Pnt2d> > myPassingPoints;
+  std::vector< std::shared_ptr<GeomAPI_Shape> > myTangentShapes;
+  std::shared_ptr<GeomAPI_Pnt2d>                myClosestPoint;
+  double                                        myRadius;
+};
+
+#endif
index 89b2c6df850b7135d98a066fecc551a9787a3991..2a9acd4b1e7e26af080be5eca8b9c84bafaa93ac 100644 (file)
@@ -24,6 +24,7 @@
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_Validator.h>
 
+#include <GeomAlgoAPI_Circ2dBuilder.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 
 #include <GeomAPI_Circ2d.h>
@@ -410,9 +411,13 @@ void calculateFilletCenter(FeaturePtr theFilletFeatures[2],
   GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
   GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
 
-  std::shared_ptr<GeomAPI_Circ2d> aFilletCircle(
-      new GeomAPI_Circ2d(aShapeA, aShapeB, theFilletRadius, theSketchPlane));
-  if (!aFilletCircle->implPtr<char>())
+  GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane);
+  aCircBuilder.addTangentCurve(aShapeA);
+  aCircBuilder.addTangentCurve(aShapeB);
+  aCircBuilder.setRadius(theFilletRadius);
+
+  std::shared_ptr<GeomAPI_Circ2d> aFilletCircle = aCircBuilder.circle();
+  if (!aFilletCircle)
     return;
 
   theCenter = aFilletCircle->center()->xy();
index 42e3b1cd5b2b64cd2fb5906983587c0ce40887f0..1c83718531ae691f2138d16f517761ee03dc0954 100644 (file)
 
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Dir.h>
-#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <GeomAlgoAPI_Circ2dBuilder.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
 
 // for sqrt on Linux
 #include <math.h>
@@ -437,18 +439,22 @@ void SketchPlugin_MacroArc::fillByThreePassedPoints()
     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
         refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt);
 
-    std::shared_ptr<GeomAPI_Interface> aPassed;
-    if (aTangentCurve)
-      aPassed = aTangentCurve;
-    else
-      aPassed = aPassedPnt;
-
-    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-    GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed, anAxis);
-    myCenter = aCircle.center();
-    aCircle = GeomAPI_Circ2d(myCenter, myStart);
+    GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+    aCircBuilder.addPassingPoint(myStart);
+    aCircBuilder.addPassingPoint(myEnd);
+    if (aTangentCurve) {
+      aCircBuilder.addTangentCurve(aTangentCurve);
+      aCircBuilder.setClosestPoint(aPassedPointAttr->pnt());
+    } else
+      aCircBuilder.addPassingPoint(aPassedPnt);
+
+    std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+    if (!aCircle)
+      return;
+    myCenter = aCircle->center();
 
-    recalculateReversedFlagByPassed(aCircle);
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+    recalculateReversedFlagByPassed(*aCircle);
   } else
     myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5)));
 }
@@ -497,11 +503,15 @@ void SketchPlugin_MacroArc::fillByTangentEdge()
   FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
   std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
 
-  std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-  GeomAPI_Circ2d aCircle(myStart, myEnd, aTangentShape, anAxis);
-  myCenter = aCircle.center();
+  GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+  aCircBuilder.addPassingPoint(myStart);
+  aCircBuilder.addPassingPoint(myEnd);
+  aCircBuilder.addTangentCurve(aTangentShape);
+
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+  myCenter = aCircle->center();
 
   // rebuild circle to set start point equal to zero parameter
-  aCircle = GeomAPI_Circ2d(myCenter, myStart);
-  recalculateReversedFlagByEnd(aCircle);
+  aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+  recalculateReversedFlagByEnd(*aCircle);
 }
index 0310207db3954ce6be56f2f2a96883bdfe57ef9a..078543b7d803ad527fc2b34eac103c984ca3f76b 100644 (file)
@@ -25,6 +25,7 @@
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Vertex.h>
 
+#include <GeomAlgoAPI_Circ2dBuilder.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_PointBuilder.h>
@@ -211,13 +212,20 @@ void SketchPlugin_MacroCircle::fillByCenterAndPassed()
       aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
 
   // Build a circle
-  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+  aCircBuilder.setCenter(aCenter);
   if (aTangentCurve) {
-    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
+    aCircBuilder.addTangentCurve(aTangentCurve);
+
+    AttributePoint2DPtr aPassedPntAttr =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
+    if (aPassedPntAttr)
+      aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
   } else
-    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
-  if (aCircle->implPtr<char>()) {
+    aCircBuilder.addPassingPoint(aPassedPoint);
+
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+  if (aCircle) {
     myCenter = aCircle->center();
     myRadius = aCircle->radius();
   }
@@ -231,7 +239,9 @@ void SketchPlugin_MacroCircle::fillByThreePoints()
   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
                                SECOND_POINT_REF_ID(),
                                THIRD_POINT_REF_ID() };
-  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
+
+  GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+
   for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
     if (!aPassedAttr->isInitialized())
@@ -245,15 +255,18 @@ void SketchPlugin_MacroCircle::fillByThreePoints()
         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
 
     if (aPassedPoint)
-      aPassedEntities[aPntIndex] = aPassedPoint;
+      aCircBuilder.addPassingPoint(aPassedPoint);
     else
-      aPassedEntities[aPntIndex] = aTangentCurve;
+      aCircBuilder.addTangentCurve(aTangentCurve);
   }
 
-  std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-  std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
-      new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
-  if (aCircle->implPtr<char>()) {
+  AttributePoint2DPtr aThirdPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+  if (aThirdPoint)
+    aCircBuilder.setClosestPoint(aThirdPoint->pnt());
+
+  std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+  if (aCircle) {
     myCenter = aCircle->center();
     myRadius = aCircle->radius();
   }
@@ -265,8 +278,10 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
                                 SECOND_POINT_ID() };
   std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
                                SECOND_POINT_REF_ID() };
+
+  GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+
   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
-  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
   int aPntIndex = 0;
   for (; aPntIndex < 2; ++aPntIndex) {
     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
@@ -281,31 +296,30 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
 
     if (aPassedPoint) {
-      aPassedEntities[aPntIndex] = aPassedPoint;
+      aCircBuilder.addPassingPoint(aPassedPoint);
       aPassedPoints[aPntIndex] = aPassedPoint;
     } else {
-      aPassedEntities[aPntIndex] = aTangentCurve;
+      aCircBuilder.addTangentCurve(aTangentCurve);
       // if the circle is tangent to any curve,
       // the third point will be initialized by the tangent point
-      aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
+      aCircBuilder.addPassingPoint(
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
     }
   }
-  if (aPntIndex <= 1)
-    return;
 
   std::shared_ptr<GeomAPI_Circ2d> aCircle;
-  if (aPassedEntities[2]) {
-    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
-    aCircle = std::shared_ptr<GeomAPI_Circ2d>(
-        new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
-  } else {
+
+  if (aPntIndex == 3)
+    aCircle = aCircBuilder.circle();
+  else if (aPntIndex == 2) {
     // the circle is defined by two points, calculate its parameters manually
     std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
         (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
         (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
   }
-  if (aCircle->implPtr<char>()) {
+
+  if (aCircle) {
     myCenter = aCircle->center();
     myRadius = aCircle->radius();
   }