]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #2024: Redesign of circle and arc of circle
authorazv <azv@opencascade.com>
Thu, 23 Mar 2017 07:25:11 +0000 (10:25 +0300)
committerdbv <dbv@opencascade.com>
Mon, 27 Mar 2017 06:56:53 +0000 (09:56 +0300)
1. Add possibility to select features while constructing circle by three points
2. Redesign of SketchPlugin_MacroCircle: move all geometric constructions to GeomAPI_Circ2d.

src/GeomAPI/GeomAPI_Circ2d.cpp
src/GeomAPI/GeomAPI_Circ2d.h
src/SketchPlugin/SketchPlugin_MacroCircle.cpp
src/SketchPlugin/SketchPlugin_MacroCircle.h

index 5edbab178a47cf77eeac99025a51608f603dc488..f4533c1440eed7bc4cc68b501b6e4716a30280f5 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 <gp_Dir2d.hxx>
 #include <gp_Circ2d.hxx>
+#include <gp_Lin2d.hxx>
 #include <gp_Pnt2d.hxx>
 #include <gp_Ax2d.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 <IntAna2d_AnaIntersection.hxx>
+#include <vector>
 
 #define MY_CIRC2D implPtr<gp_Circ2d>()
 
+typedef std::shared_ptr<Geom2dAdaptor_Curve>  CurveAdaptorPtr;
+
+class CircleBuilder
+{
+public:
+  CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
+    : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>()))
+  {}
+
+  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;
+    CurveAdaptorPtr aCurve(new Geom2dAdaptor_Curve(
+        BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast)));
+
+    myTangentShapes.push_back(aCurve);
+  }
+
+  void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+  {
+    myPassingPoints.push_back(thePoint->impl<gp_Pnt2d>());
+  }
+
+  gp_Circ2d* circle()
+  {
+    gp_Circ2d* aResult = 0;
+    if (myCenter) {
+      if (myPassingPoints.size() == 1)
+        aResult = circleByCenterAndPassingPoint();
+      else if (myTangentShapes.size() == 1)
+        aResult = circleByCenterAndTangent();
+    } 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:
+  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 (aPonTgCurve >= aCurve->FirstParameter() && aPonTgCurve <= aCurve->LastParameter()) {
+        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()
+  {
+    std::shared_ptr<GccEnt_QualifiedCirc> aTgCirc[3];
+    std::shared_ptr<GccEnt_QualifiedLin>  aTgLine[3];
+    int aNbTgCirc = 0;
+    int aNbTgLine = 0;
+
+    std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
+    for (; anIt != myTangentShapes.end(); ++anIt) {
+      switch ((*anIt)->GetType()) {
+      case GeomAbs_Line:
+        aTgLine[aNbTgLine++] = std::shared_ptr<GccEnt_QualifiedLin>(
+            new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified));
+        break;
+      case GeomAbs_Circle:
+        aTgCirc[aNbTgCirc++] = std::shared_ptr<GccEnt_QualifiedCirc>(
+            new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified));
+        break;
+      default:
+        break;
+      }
+    }
+    if (aNbTgCirc + aNbTgLine != 3)
+      return 0;
+
+    std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
+    switch (aNbTgLine) {
+    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 (aCurve2->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 = aPonTgCurve >= myTangentShapes[0]->FirstParameter() &&
+                       aPonTgCurve <= myTangentShapes[0]->LastParameter();
+      }
+      if (myTangentShapes.size() >= 2 && isApplicable) {
+        theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = aPonTgCurve >= myTangentShapes[1]->FirstParameter() &&
+                       aPonTgCurve <= myTangentShapes[1]->LastParameter();
+      }
+      if (myTangentShapes.size() >= 3 && isApplicable) {
+        theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
+        isApplicable = aPonTgCurve >= myTangentShapes[2]->FirstParameter() &&
+                       aPonTgCurve <= myTangentShapes[2]->LastParameter();
+      }
+
+      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;
+  }
+
+private:
+  Handle(Geom_Plane) myPlane;
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::vector<gp_Pnt2d> myPassingPoints;
+  std::vector<CurveAdaptorPtr> myTangentShapes;
+};
+
+typedef std::shared_ptr<CircleBuilder> CircleBuilderPtr;
+
+
 static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, const gp_Dir2d theDir,
                             const double theRadius)
 {
@@ -87,6 +394,8 @@ static gp_Circ2d* newCirc2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
   return newCirc2d(aCenter.X(), aCenter.Y(), aDir, aRadius);
 }
 
+
+
 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
                                const std::shared_ptr<GeomAPI_Pnt2d>& theCirclePoint)
     : GeomAPI_Interface(
@@ -108,6 +417,29 @@ GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoi
 {
 }
 
+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());
+}
+
+
 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
     const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
 {
index df362c3e87d6c1e2a7c98bafdecd116924ffcdeb..0777ad3540e384c5411c1074f341a8b42d08c91a 100644 (file)
 #include <GeomAPI_Interface.h>
 #include <memory>
 
+class GeomAPI_Ax3;
 class GeomAPI_Pnt2d;
 class GeomAPI_Dir2d;
+class GeomAPI_Shape;
 
 /**\class GeomAPI_Circ2d
  * \ingroup DataModel
@@ -37,6 +39,20 @@ class GeomAPI_Circ2d : public GeomAPI_Interface
                  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);
+
   /// Return center of the circle
   GEOMAPI_EXPORT
   const std::shared_ptr<GeomAPI_Pnt2d> center() const;
index 89d1373481ef698160f2ea23d59a7b4ac9ec60ea..375fec58813de9bd1457a0d19192ca2d23130620 100644 (file)
@@ -7,7 +7,8 @@
 #include "SketchPlugin_MacroCircle.h"
 
 #include "SketchPlugin_Circle.h"
-#include "SketchPlugin_ConstraintCoincidence.h"
+//#include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_Point.h"
 #include "SketchPlugin_Tools.h"
 
 #include <ModelAPI_Data.h>
@@ -22,7 +23,6 @@
 
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Circ.h>
-#include <GeomAPI_Circ2d.h>
 #include <GeomAPI_Vertex.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
@@ -67,28 +67,74 @@ void SketchPlugin_MacroCircle::initAttributes()
   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
 
   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
 
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
 }
 
 void SketchPlugin_MacroCircle::execute()
 {
-  // Create circle feature.
-  FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
-  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
-                                                                             myCenter->y());
-  aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
-  aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
-                ->setValue(boolean(AUXILIARY_ID())->value());
-  aCircleFeature->execute();
+  std::string aType = string(CIRCLE_TYPE())->value();
+  if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
+    createCircleByCenterAndPassed();
+  else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
+    createCircleByThreePoints();
 
   myCenter.reset();
   myRadius = 0;
+}
+
+static void convertToPointOrTangent(const AttributeRefAttrPtr&      theRefAttr,
+                                    const AttributePtr&             theBaseAttr,
+                                    std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint,
+                                    std::shared_ptr<GeomAPI_Shape>& theTangentCurve)
+{
+  AttributePtr anAttr = theBaseAttr;
+  if (theRefAttr->isObject()) {
+    FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
+    if (aTgFeature) {
+      if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
+        theTangentCurve = aTgFeature->lastResult()->shape();
+        return;
+      }
+      anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
+    }
+  } else
+    anAttr = theRefAttr->attr();
+
+  thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
+}
+
+void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
+{
+  AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
+  AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
+  // Calculate circle parameters
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+  std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+  convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
+
+  // Build a circle
+  std::shared_ptr<GeomAPI_Circ2d> aCircle;
+  if (aTangentCurve) {
+    std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
+  } else
+    aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
+
+  // Create circle feature.
+  FeaturePtr aCircleFeature = createCircleFeature(aCircle);
 
   // Create constraints.
   SketchPlugin_Tools::createConstraint(this,
@@ -103,6 +149,57 @@ void SketchPlugin_MacroCircle::execute()
                                        true);
 }
 
+void SketchPlugin_MacroCircle::createCircleByThreePoints()
+{
+  std::string aPointAttr[3] = { FIRST_POINT_ID(),
+                                SECOND_POINT_ID(),
+                                THIRD_POINT_ID() };
+  std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
+                               SECOND_POINT_REF_ID(),
+                               THIRD_POINT_REF_ID() };
+  std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
+  for (int i = 0; i < 3; ++i) {
+    AttributePtr aPassedAttr = attribute(aPointAttr[i]);
+    AttributeRefAttrPtr aPassedRef = refattr(aPointRef[i]);
+    // calculate circle parameters
+    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+    convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
+
+    if (aPassedPoint)
+      aPassedEntities[i] = aPassedPoint;
+    else
+      aPassedEntities[i] = 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));
+
+  // Create circle feature.
+  FeaturePtr aCircleFeature = createCircleFeature(aCircle);
+  ResultPtr aCircleResult = aCircleFeature->lastResult();
+
+  // Create constraints.
+  for (int i = 0; i < 3; ++i)
+    SketchPlugin_Tools::createConstraint(this, aPointRef[i], NULL, aCircleResult, true);
+}
+
+FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
+    const std::shared_ptr<GeomAPI_Circ2d>& theCircle)
+{
+  FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter = theCircle->center();
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCenter->x(),
+                                                                             aCenter->y());
+  aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(theCircle->radius());
+  aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
+                ->setValue(boolean(AUXILIARY_ID())->value());
+  aCircleFeature->execute();
+  return aCircleFeature;
+}
+
 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
 {
   if(!myCenter.get() || myRadius < tolerance) {
index 4ea0ecc50262dc3b15accd2d5e8083a2be4567f7..bc387acd518e7703401f9372f2f7af52163cf2bc 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <GeomAPI_IPresentable.h>
 #include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Circ2d.h>
 
 /**\class SketchPlugin_MacroCircle
  * \ingroup Plugins
@@ -85,6 +86,13 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  /// Reference for first point selection.
+  inline static const std::string& FIRST_POINT_REF_ID()
+  {
+    static const std::string ID("first_point_ref");
+    return ID;
+  }
+
   /// Second point id.
   inline static const std::string& SECOND_POINT_ID()
   {
@@ -92,6 +100,13 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  /// Reference for second point selection.
+  inline static const std::string& SECOND_POINT_REF_ID()
+  {
+    static const std::string ID("second_point_ref");
+    return ID;
+  }
+
   /// Third point id.
   inline static const std::string& THIRD_POINT_ID()
   {
@@ -99,6 +114,13 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity,
     return ID;
   }
 
+  /// Reference for third point selection.
+  inline static const std::string& THIRD_POINT_REF_ID()
+  {
+    static const std::string ID("third_point_ref");
+    return ID;
+  }
+
   /// Radius of the circle
   inline static const std::string& CIRCLE_RADIUS_ID()
   {
@@ -143,6 +165,11 @@ class SketchPlugin_MacroCircle: public SketchPlugin_SketchEntity,
 private:
   void resetAttribute(const std::string& theId);
 
+  void createCircleByCenterAndPassed();
+  void createCircleByThreePoints();
+
+  FeaturePtr createCircleFeature(const std::shared_ptr<GeomAPI_Circ2d>& theCircle);
+
 private:
   std::shared_ptr<GeomAPI_Pnt2d> myCenter;
   double myRadius;