Salome HOME
Task 2.1. Creation of ellipses and arcs of ellipse.
authorazv <azv@opencascade.com>
Thu, 27 Apr 2017 04:47:33 +0000 (07:47 +0300)
committerazv <azv@opencascade.com>
Thu, 27 Apr 2017 04:47:52 +0000 (07:47 +0300)
Sketch feature Ellipse has been implemented from skratch

16 files changed:
src/GeomAPI/CMakeLists.txt
src/GeomAPI/GeomAPI_Ellipse.cpp
src/GeomAPI/GeomAPI_Ellipse.h
src/GeomAPI/GeomAPI_Ellipse2d.cpp [new file with mode: 0644]
src/GeomAPI/GeomAPI_Ellipse2d.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Ellipse.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Ellipse.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroCircle.cpp
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroEllipse.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/icons/ellipse.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml

index d76e17b78e54fb3e3dd691997713f4c0d980a085..ca8d2855ce6128891a0c3fee58181e528bb364fc 100644 (file)
@@ -38,7 +38,8 @@ SET(PROJECT_HEADERS
     GeomAPI_Trsf.h
     GeomAPI_Angle2d.h
     GeomAPI_Wire.h
-       GeomAPI_Ellipse.h
+    GeomAPI_Ellipse.h
+    GeomAPI_Ellipse2d.h
 )
 
 SET(PROJECT_SOURCES
@@ -73,7 +74,8 @@ SET(PROJECT_SOURCES
     GeomAPI_Trsf.cpp
     GeomAPI_Angle2d.cpp
     GeomAPI_Wire.cpp
-       GeomAPI_Ellipse.cpp
+    GeomAPI_Ellipse.cpp
+    GeomAPI_Ellipse2d.cpp
 )
 
 SET(PROJECT_LIBRARIES
index 1eae6445f4e532683b4b5abc36e3ec7d7f3c36ac..2d47a5a6f7a9612d68505f303b05821b8a69bdb3 100644 (file)
@@ -18,6 +18,12 @@ GeomAPI_Ellipse::GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
 {
 }
 
+std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::center() const
+{
+  const gp_Pnt& aCenter = MY_ELIPS->Location();
+  return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCenter.X(), aCenter.Y(), aCenter.Z()));
+}
+
 GeomPointPtr GeomAPI_Ellipse::firstFocus() const
 {
   const gp_Pnt& aFirst = MY_ELIPS->Focus1();
index a855e189ba856beca5e5509d19388dc057e90133..d201d127ac22b2204e879b97be66ccab31035b4a 100644 (file)
@@ -35,10 +35,13 @@ public:
   GEOMAPI_EXPORT GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
                                  double theMajorRadius, double theMinorRadius);
 
-  /// Returns first center of the ellipse
+  /// Returns center of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> center() const;
+
+  /// Returns first focus of the ellipse
   GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> firstFocus() const;
 
-  /// Returns second center of the ellipse
+  /// Returns second focus of the ellipse
   GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> secondFocus() const;
 
   /// Returns minor radius of the ellipse
diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.cpp b/src/GeomAPI/GeomAPI_Ellipse2d.cpp
new file mode 100644 (file)
index 0000000..eca8f4a
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File:        GeomAPI_Ellipse2d.cpp
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <gp_Ax22d.hxx>
+#include <gp_Elips2d.hxx>
+#include <Precision.hxx>
+
+#define MY_ELLIPSE implPtr<gp_Elips2d>()
+
+static gp_Elips2d* newEllipse(const gp_Pnt2d& theCenter,
+                              const gp_Dir2d& theXAxis,
+                              const double theMajorRadius,
+                              const double theMinorRadius)
+{
+  if (theMajorRadius < theMinorRadius - Precision::Confusion()) {
+    return newEllipse(theCenter, gp_Dir2d(-theXAxis.Y(), theXAxis.X()),
+                      theMinorRadius, theMajorRadius);
+  }
+
+  gp_Ax22d anAxis(theCenter, theXAxis);
+  return new gp_Elips2d(anAxis, theMajorRadius, theMinorRadius);
+}
+
+static gp_Elips2d* newEllipse(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                              const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                              const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
+{
+  const gp_Pnt2d& aCenter = theCenter->impl<gp_Pnt2d>();
+  const gp_Pnt2d& anAxisPnt = theAxisPoint->impl<gp_Pnt2d>();
+  const gp_Pnt2d& aPassedPnt = thePassingPoint->impl<gp_Pnt2d>();
+
+  gp_Dir2d aXAxis(anAxisPnt.XY() - aCenter.XY());
+  double aMajorRadius = anAxisPnt.Distance(aCenter);
+
+  gp_XY aPassedDir = aPassedPnt.XY() - aCenter.XY();
+
+  double X = aPassedDir.Dot(aXAxis.XY()) / aMajorRadius;
+  if (Abs(X) > 1.0 - Precision::Confusion())
+    return 0; // ellipse cannot be created for such parameters
+
+  double Y = aPassedDir.CrossMagnitude(aXAxis.XY());
+  double aMinorRadius = Y / Sqrt(1. - X * X);
+
+  return newEllipse(aCenter, aXAxis, aMajorRadius, aMinorRadius);
+}
+
+
+GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                     const std::shared_ptr<GeomAPI_Dir2d>& theXAxis,
+                                     const double theMajorRadius,
+                                     const double theMinorRadius)
+  : GeomAPI_Interface(newEllipse(theCenter->impl<gp_Pnt2d>(), theXAxis->impl<gp_Dir2d>(),
+                                 theMajorRadius, theMinorRadius))
+{
+}
+
+GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                                     const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
+  : GeomAPI_Interface(newEllipse(theCenter, theAxisPoint, thePassingPoint))
+{
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::center() const
+{
+  const gp_Pnt2d& aCenter = MY_ELLIPSE->Location();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::firstFocus() const
+{
+  const gp_Pnt2d& aFirst = MY_ELLIPSE->Focus1();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aFirst.X(), aFirst.Y()));
+}
+
+std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::secondFocus() const
+{
+  const gp_Pnt2d& aSecond = MY_ELLIPSE->Focus2();
+  return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aSecond.X(), aSecond.Y()));
+}
+
+double GeomAPI_Ellipse2d::minorRadius() const
+{
+  return MY_ELLIPSE->MinorRadius();
+}
+
+double GeomAPI_Ellipse2d::majorRadius() const
+{
+  return MY_ELLIPSE->MajorRadius();
+}
diff --git a/src/GeomAPI/GeomAPI_Ellipse2d.h b/src/GeomAPI/GeomAPI_Ellipse2d.h
new file mode 100644 (file)
index 0000000..293c956
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File:        GeomAPI_Ellipse2d.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef GeomAPI_Ellipse2d_H_
+#define GeomAPI_Ellipse2d_H_
+
+#include <GeomAPI_Interface.h>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_Dir2d;
+
+/**\class GeomAPI_Ellipse2d
+ * \ingroup DataModel
+ * \brief Ellipse in 2D
+ */
+class GeomAPI_Ellipse2d : public GeomAPI_Interface
+{
+public:
+  /// \brief Constructs ellipse by center, X-axis and given radii
+  GEOMAPI_EXPORT GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                   const std::shared_ptr<GeomAPI_Dir2d>& theXAxis,
+                                   const double theMajorRadius,
+                                   const double theMinorRadius);
+
+  /// \brief Constructs ellipse by center and two points lying on the ellipse:
+  ///        first of them defines an axis of the ellipse
+  ///        and another is just placed on the ellipse.
+  GEOMAPI_EXPORT GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
+                                   const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint);
+
+  /// Returns center of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> center() const;
+
+  /// Returns first focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> firstFocus() const;
+
+  /// Returns second focus of the ellipse
+  GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt2d> secondFocus() const;
+
+  /// Returns minor radius of the ellipse
+  GEOMAPI_EXPORT double minorRadius() const;
+
+  /// Returns major radius of the ellipse
+  GEOMAPI_EXPORT double majorRadius() const;
+};
+
+#endif
index a1ada3eca4646509a46838e02f1e0a977646a247..b10bbf736a8e883130d7752aa305c3a9e99f8558 100644 (file)
@@ -5,20 +5,21 @@
 // Author:      Mikhail PONIKAROV
 
 #include <GeomAlgoAPI_EdgeBuilder.h>
-#include <gp_Pln.hxx>
-#include <BRepBuilderAPI_MakeEdge.hxx>
-#include <TopoDS_Edge.hxx>
-#include <TopoDS_Face.hxx>
-#include <TopoDS.hxx>
-#include <BRep_Tool.hxx>
-#include <Geom_Plane.hxx>
-#include <Geom_CylindricalSurface.hxx>
-#include <Geom_RectangularTrimmedSurface.hxx>
 
-#include <gp_Ax2.hxx>
-#include <gp_Circ.hxx>
 #include <Bnd_Box.hxx>
+#include <BRep_Tool.hxx>
 #include <BRepBndLib.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <gp_Ax2.hxx>
+#include <gp_Circ.hxx>
+#include <gp_Elips.hxx>
+#include <gp_Pln.hxx>
+#include <Geom_CylindricalSurface.hxx>
+#include <Geom_Plane.hxx>
+#include <Geom_RectangularTrimmedSurface.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
 
 std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::line(
     std::shared_ptr<GeomAPI_Pnt> theStart, std::shared_ptr<GeomAPI_Pnt> theEnd)
@@ -208,3 +209,23 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::lineCircleArc(
   }
   return aRes;
 }
+
+std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipse(
+    const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+    const std::shared_ptr<GeomAPI_Dir>& theNormal,
+    const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+    const double                        theMajorRadius,
+    const double                        theMinorRadius)
+{
+  const gp_Pnt& aCenter = theCenter->impl<gp_Pnt>();
+  const gp_Dir& aNormal = theNormal->impl<gp_Dir>();
+  const gp_Dir& aMajorAxis = theMajorAxis->impl<gp_Dir>();
+
+  gp_Elips anEllipse(gp_Ax2(aCenter, aNormal, aMajorAxis), theMajorRadius, theMinorRadius);
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(anEllipse);
+  std::shared_ptr<GeomAPI_Edge> aRes(new GeomAPI_Edge);
+  TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+  aRes->setImpl(new TopoDS_Shape(anEdge));
+  return aRes;
+}
index a781ce219ac8ca76356f73c5ad29611fa0a4ad62..a77693e51463398425aa37a0ec145ae8fb9f18f3 100644 (file)
@@ -58,6 +58,13 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
                                                        std::shared_ptr<GeomAPI_Pnt> theStartPoint,
                                                        std::shared_ptr<GeomAPI_Pnt> theEndPoint,
                                                        std::shared_ptr<GeomAPI_Dir> theNormal);
+
+  /// Creates elliptic edge
+  static std::shared_ptr<GeomAPI_Edge> ellipse(const std::shared_ptr<GeomAPI_Pnt>& theCenter,
+                                               const std::shared_ptr<GeomAPI_Dir>& theNormal,
+                                               const std::shared_ptr<GeomAPI_Dir>& theMajorAxis,
+                                               const double                        theMajorRadius,
+                                               const double                        theMinorRadius);
 };
 
 #endif
index 3f8723de769fc39c98c174d936917702ccd3b06a..010ee47f9e4ac46899f98fee3416bca0497b2cf4 100644 (file)
@@ -14,7 +14,6 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
     SketchPlugin_ConstraintEqual.h
-    SketchPlugin_Fillet.h
     SketchPlugin_ConstraintHorizontal.h
     SketchPlugin_ConstraintLength.h
     SketchPlugin_ConstraintMiddle.h
@@ -26,13 +25,16 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintSplit.h
     SketchPlugin_ConstraintTangent.h
     SketchPlugin_ConstraintVertical.h
+    SketchPlugin_Ellipse.h
     SketchPlugin_ExternalValidator.h
     SketchPlugin_Feature.h
+    SketchPlugin_Fillet.h
     SketchPlugin_IntersectionPoint.h
     SketchPlugin_Line.h
     SketchPlugin_MacroArc.h
     SketchPlugin_MacroArcReentrantMessage.h
     SketchPlugin_MacroCircle.h
+    SketchPlugin_MacroEllipse.h
     SketchPlugin_MultiRotation.h
     SketchPlugin_MultiTranslation.h
     SketchPlugin_Plugin.h
@@ -55,7 +57,6 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
     SketchPlugin_ConstraintEqual.cpp
-    SketchPlugin_Fillet.cpp
     SketchPlugin_ConstraintHorizontal.cpp
     SketchPlugin_ConstraintLength.cpp
     SketchPlugin_ConstraintMiddle.cpp
@@ -67,12 +68,15 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintSplit.cpp
     SketchPlugin_ConstraintTangent.cpp
     SketchPlugin_ConstraintVertical.cpp
+    SketchPlugin_Ellipse.cpp
     SketchPlugin_ExternalValidator.cpp
     SketchPlugin_Feature.cpp
+    SketchPlugin_Fillet.cpp
     SketchPlugin_IntersectionPoint.cpp
     SketchPlugin_Line.cpp
     SketchPlugin_MacroArc.cpp
     SketchPlugin_MacroCircle.cpp
+    SketchPlugin_MacroEllipse.cpp
     SketchPlugin_MultiRotation.cpp
     SketchPlugin_MultiTranslation.cpp
     SketchPlugin_Plugin.cpp
diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.cpp b/src/SketchPlugin/SketchPlugin_Ellipse.cpp
new file mode 100644 (file)
index 0000000..2317e05
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D -->
+
+// File:        SketchPlugin_Ellipse.cpp
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+static const double tolerance = 1e-7;
+
+
+SketchPlugin_Ellipse::SketchPlugin_Ellipse()
+: SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_Ellipse::initDerivedClassAttributes()
+{
+  data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(FOCUS_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_Ellipse::execute()
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    return;
+  }
+
+  // Compute a ellipse in 3D view.
+  std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FOCUS_ID()));
+  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
+  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+  if (!aCenterAttr->isInitialized() ||
+      !aFocusAttr->isInitialized() ||
+      !aMajorRadiusAttr->isInitialized() ||
+      !aMinorRadiusAttr->isInitialized()) {
+    return;
+  }
+
+  double aMajorRadius = aMajorRadiusAttr->value();
+  double aMinorRadius = aMinorRadiusAttr->value();
+  if(aMajorRadius < tolerance || aMinorRadius < tolerance) {
+    return;
+  }
+
+  // Make a visible point.
+  SketchPlugin_Sketch::createPoint2DResult(this, aSketch, CENTER_ID(), 0);
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  // Make a visible ellipse.
+  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
+  std::shared_ptr<GeomAPI_Pnt> aFocus(aSketch->to3D(aFocusAttr->x(), aFocusAttr->y()));
+  std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
+  std::shared_ptr<GeomAPI_Dir> aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+      aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape =
+      GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, aMajorRadius, aMinorRadius);
+
+  std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 1);
+  aResult->setShape(anEllipseShape);
+  aResult->setIsInHistory(false);
+  setResult(aResult, 1);
+}
+
+void SketchPlugin_Ellipse::move(double theDeltaX, double theDeltaY)
+{
+  std::shared_ptr<ModelAPI_Data> aData = data();
+  if(!aData->isValid()) {
+    return;
+  }
+
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aData->attribute(CENTER_ID()));
+  if(aPoint->isInitialized()) {
+    aPoint->move(theDeltaX, theDeltaY);
+  }
+}
+
+bool SketchPlugin_Ellipse::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_Ellipse::attributeChanged(const std::string& theID) {
+  // the second condition for unability to move external segments anywhere
+  if (theID == EXTERNAL_ID() || isFixed()) {
+    std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+    if (!aSelection) {
+      // empty shape in selection shows that the shape is equal to context
+      ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+      if (anExtRes)
+        aSelection = anExtRes->shape();
+    }
+    // update arguments due to the selection value
+    if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+      std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
+      std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+
+      std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+      aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+
+      std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FOCUS_ID()));
+      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+
+      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+    }
+  }
+}
diff --git a/src/SketchPlugin/SketchPlugin_Ellipse.h b/src/SketchPlugin/SketchPlugin_Ellipse.h
new file mode 100644 (file)
index 0000000..287a1a5
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D -->
+
+// File:        SketchPlugin_Ellipse.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef SketchPlugin_Ellipse_H_
+#define SketchPlugin_Ellipse_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_Ellipse
+ * \ingroup Plugins
+ * \brief Feature for creation of the new ellipse in Sketch.
+ */
+class SketchPlugin_Ellipse: public SketchPlugin_SketchEntity
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchEllipse");
+    return ID;
+  }
+
+  /// 2D point - center of the ellipse
+  inline static const std::string& CENTER_ID()
+  {
+    static const std::string ID("ellipse_center");
+    return ID;
+  }
+
+  /// 2D point - focus of the ellipse
+  inline static const std::string& FOCUS_ID()
+  {
+    static const std::string ID("ellipse_focus");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_minor_radius");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_Ellipse::ID();
+    return MY_KIND;
+  }
+
+  /// Returns true is sketch element is under the rigid constraint
+  SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Moves the feature
+  /// \param theDeltaX the delta for X coordinate is moved
+  /// \param theDeltaY the delta for Y coordinate is moved
+  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_Ellipse();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+};
+
+#endif
index 3af61c721b52505313a428b5336377ff8bf5b703..6b24fc7257f53638b3be5208879582da4a5ef33e 100644 (file)
@@ -373,7 +373,6 @@ AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
 }
 
 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
-  double aRadius = 0.0;
   // If circle type switched reset all attributes.
   if(theID == CIRCLE_TYPE()) {
     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp b/src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
new file mode 100644 (file)
index 0000000..77a04c9
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D -->
+
+// File:        SketchPlugin_MacroEllipse.cpp
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#include <SketchPlugin_MacroEllipse.h>
+
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Events.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Vertex.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+
+SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
+: SketchPlugin_SketchEntity(),
+  myMajorRadius(0.0),
+  myMinorRadius(0.0)
+{
+}
+
+void SketchPlugin_MacroEllipse::initAttributes()
+{
+  data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
+  data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
+
+  data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(MINOR_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(), MAJOR_AXIS_POINT_REF_ID());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
+}
+
+void SketchPlugin_MacroEllipse::execute()
+{
+  FeaturePtr anEllipse = createEllipseFeature();
+  constraintsForEllipse(anEllipse);
+
+  // message to init reentrant operation
+  static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+  ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+  aMessage->setCreatedFeature(anEllipse);
+  Events_Loop::loop()->send(aMessage);
+}
+
+void SketchPlugin_MacroEllipse::attributeChanged(const std::string& theID)
+{
+  static const int NB_POINTS = 3;
+  std::string aPointAttrName[NB_POINTS] = { CENTER_POINT_ID(),
+                                            MAJOR_AXIS_POINT_ID(),
+                                            PASSED_POINT_ID() };
+  std::string aPointRefName[NB_POINTS] = { CENTER_POINT_REF_ID(),
+                                           MAJOR_AXIS_POINT_REF_ID(),
+                                           PASSED_POINT_REF_ID() };
+
+  int aNbInitialized = 0;
+  std::shared_ptr<GeomAPI_Pnt2d> anEllipsePoints[NB_POINTS];
+
+  for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
+    AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
+    if (!aPointAttr->isInitialized())
+      continue;
+
+    AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
+    // calculate ellipse parameters
+    std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
+    std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+    SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+        aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
+
+    anEllipsePoints[aNbInitialized++] = aPassedPoint;
+  }
+
+  std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
+  if (aNbInitialized == 2) {
+    std::shared_ptr<GeomAPI_Dir2d> aXDir(new GeomAPI_Dir2d(
+        anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
+        anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
+    double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+        new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
+  } else if (aNbInitialized == 3) {
+    anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
+        new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
+  }
+
+  if (!anEllipse || anEllipse->implPtr<void>() == 0)
+    return;
+
+  myCenter = anEllipse->center();
+  myFocus = anEllipse->firstFocus();
+  myMajorRadius = anEllipse->majorRadius();
+  myMinorRadius = anEllipse->minorRadius();
+
+  AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
+  AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+  // center attribute is used in processEvent() to set reference to reentrant arc
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->setValue(myCenter);
+  aMajorRadiusAttr->setValue(myMajorRadius);
+  aMinorRadiusAttr->setValue(myMinorRadius);
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
+}
+
+std::string SketchPlugin_MacroEllipse::processEvent(
+                                              const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::string aFilledAttributeName;
+
+  ReentrantMessagePtr aReentrantMessage =
+        std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+  if (aReentrantMessage) {
+    FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+    ObjectPtr anObject = aReentrantMessage->selectedObject();
+    AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+    std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+    if (aClickedPoint && (anObject || anAttribute)) {
+      aFilledAttributeName = CENTER_POINT_ID();
+      std::string aReferenceAttributeName = CENTER_POINT_REF_ID();
+
+      // fill 2d point attribute
+      AttributePoint2DPtr aPointAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(aFilledAttributeName));
+      aPointAttr->setValue(aClickedPoint);
+
+      // fill reference attribute
+      AttributeRefAttrPtr aRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(attribute(aReferenceAttributeName));
+      if (anAttribute) {
+        if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+          if (aCreatedFeature && anAttribute->id() == CENTER_POINT_ID())
+            anAttribute = aCreatedFeature->attribute(SketchPlugin_Ellipse::CENTER_ID());
+        }
+        aRefAttr->setAttr(anAttribute);
+      }
+      else if (anObject.get()) {
+        // if presentation of previous reentrant macro arc is used, the object is invalid,
+        // we should use result of previous feature of the message(Arc)
+        if (!anObject->data()->isValid())
+          anObject = aCreatedFeature->lastResult();
+        aRefAttr->setObject(anObject);
+      }
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  }
+  return aFilledAttributeName;
+}
+
+void SketchPlugin_MacroEllipse::constraintsForEllipse(FeaturePtr theEllipseFeature)
+{
+  // Create constraints.
+  SketchPlugin_Tools::createConstraint(
+      this, CENTER_POINT_REF_ID(),
+      theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+      ObjectPtr(), false);
+  SketchPlugin_Tools::createConstraint(
+      this, MAJOR_AXIS_POINT_REF_ID(), AttributePtr(),
+      theEllipseFeature->lastResult(), true);
+  SketchPlugin_Tools::createConstraint(
+      this, PASSED_POINT_REF_ID(), AttributePtr(),
+      theEllipseFeature->lastResult(), true);
+}
+
+FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
+{
+  FeaturePtr aEllipseFeature = sketch()->addFeature(SketchPlugin_Ellipse::ID());
+
+  AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()));
+  aCenterAttr->setValue(myCenter->x(), myCenter->y());
+
+  AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aEllipseFeature->attribute(SketchPlugin_Ellipse::FOCUS_ID()));
+  aFocusAttr->setValue(myFocus->x(), myFocus->y());
+
+  aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
+  aEllipseFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(myMinorRadius);
+
+  aEllipseFeature->boolean(SketchPlugin_Ellipse::AUXILIARY_ID())->setValue(
+      boolean(AUXILIARY_ID())->value());
+
+  aEllipseFeature->execute();
+  return aEllipseFeature;
+}
+
+AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch || !myCenter || myMajorRadius == 0)
+    return AISObjectPtr();
+
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+      aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+
+  // Compute a ellipse in 3D view.
+  std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
+  std::shared_ptr<GeomAPI_Pnt> aFocus(aSketch->to3D(myFocus->x(), myFocus->y()));
+  std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
+  std::shared_ptr<GeomAPI_Dir> aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
+      aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
+
+  std::shared_ptr<GeomAPI_Shape> anEllipseShape =
+      GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, myMajorRadius, myMinorRadius);
+  GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
+  if (!anEllipseShape.get() || !aCenterPointShape.get())
+    return AISObjectPtr();
+
+  std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
+  aShapes.push_back(anEllipseShape);
+  aShapes.push_back(aCenterPointShape);
+
+  std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS)
+    anAIS.reset(new GeomAPI_AISObject());
+  anAIS->createShape(aCompound);
+  return anAIS;
+}
diff --git a/src/SketchPlugin/SketchPlugin_MacroEllipse.h b/src/SketchPlugin/SketchPlugin_MacroEllipse.h
new file mode 100644 (file)
index 0000000..29ae089
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D -->
+
+// File:        SketchPlugin_MacroEllipse.h
+// Created:     26 April 2017
+// Author:      Artem ZHIDKOV
+
+#ifndef SketchPlugin_MacroEllipse_H_
+#define SketchPlugin_MacroEllipse_H_
+
+#include <ModelAPI_IReentrant.h>
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+#include <GeomAPI_IPresentable.h>
+
+////class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+/**\class SketchPlugin_MacroEllipse
+ * \ingroup Plugins
+ * \brief Feature for creation of the new ellipse in Sketch.
+ */
+class SketchPlugin_MacroEllipse: public SketchPlugin_SketchEntity,
+                                 public GeomAPI_IPresentable,
+                                 public ModelAPI_IReentrant
+{
+ public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroEllipse");
+    return ID;
+  }
+
+  /// 2D point - center of the ellipse.
+  inline static const std::string& CENTER_POINT_ID()
+  {
+    static const std::string ID("center_point");
+    return ID;
+  }
+
+  /// Reference for center point selection.
+  inline static const std::string& CENTER_POINT_REF_ID()
+  {
+    static const std::string ID("center_point_ref");
+    return ID;
+  }
+
+  /// 2D point - major axis point of the ellipse.
+  inline static const std::string& MAJOR_AXIS_POINT_ID()
+  {
+    static const std::string ID("major_axis_point");
+    return ID;
+  }
+
+  /// Reference for major axis point selection.
+  inline static const std::string& MAJOR_AXIS_POINT_REF_ID()
+  {
+    static const std::string ID("major_axis_point_ref");
+    return ID;
+  }
+
+  /// 2D point - passed point of the ellipse
+  inline static const std::string& PASSED_POINT_ID()
+  {
+    static const std::string ID("passed_point");
+    return ID;
+  }
+
+  /// Reference for passed point selection.
+  inline static const std::string& PASSED_POINT_REF_ID()
+  {
+    static const std::string ID("passed_point_ref");
+    return ID;
+  }
+
+  /// Major radius of the ellipse
+  inline static const std::string& MAJOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_major_radius");
+    return ID;
+  }
+
+  /// Minor radius of the ellipse
+  inline static const std::string& MINOR_RADIUS_ID()
+  {
+    static const std::string ID("ellipse_minor_radius");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_MacroEllipse::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes.
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Returns the AIS preview
+  virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Moves the feature
+  /// \param theDeltaX the delta for X coordinate is moved
+  /// \param theDeltaY the delta for Y coordinate is moved
+  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY)
+  {}
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const
+  {return true;}
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const
+  {return false;}
+
+  /// Apply information of the message to current object. It fills reference object,
+  /// tangent type and tangent point refence in case of tangent arc
+  virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_MacroEllipse();
+
+private:
+  void constraintsForEllipse(FeaturePtr theEllipseFeature);
+
+  FeaturePtr createEllipseFeature();
+
+private:
+  std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+  std::shared_ptr<GeomAPI_Pnt2d> myFocus;
+  double                         myMajorRadius;
+  double                         myMinorRadius;
+};
+
+#endif
index e6451367d112de681be2f3ffa3f218237bc7830b..9999ea08c7ca04c7fe3788709e047191f3c9b151 100644 (file)
@@ -32,6 +32,8 @@
 #include <SketchPlugin_Trim.h>
 #include <SketchPlugin_Validators.h>
 #include <SketchPlugin_ExternalValidator.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_MacroEllipse.h>
 
 #include <Events_Loop.h>
 #include <GeomDataAPI_Dir.h>
@@ -208,6 +210,10 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_MacroArc);
   } else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
     return FeaturePtr(new SketchPlugin_MacroCircle);
+  } else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
+    return FeaturePtr(new SketchPlugin_Ellipse);
+  } else if (theFeatureID == SketchPlugin_MacroEllipse::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroEllipse);
   }
   // feature of such kind is not found
   return FeaturePtr();
diff --git a/src/SketchPlugin/icons/ellipse.png b/src/SketchPlugin/icons/ellipse.png
new file mode 100644 (file)
index 0000000..6f31163
Binary files /dev/null and b/src/SketchPlugin/icons/ellipse.png differ
index 45cb3cec847c52b5fa4f71ba300640e64c82d750..e33f3dede8309a80a9095bfaaa38f0ee984f3d84 100644 (file)
@@ -7,6 +7,7 @@
         id="Sketch"
         nested="SketchPoint SketchIntersectionPoint SketchLine
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
+                SketchEllipse SketchMacroEllipse
                 SketchRectangle
                 SketchProjection
                 SketchConstraintLength SketchConstraintRadius SketchConstraintDistance
       </feature>
     </group>
 
+    <group id="Elliptic geometry">
+      <!-- SketchEllipse is a hidden feature. It is created inside SketchMacroEllipse. -->
+      <feature id="SketchEllipse"
+               title="Ellipse"
+               tooltip="Create ellipse"
+               icon="icons/Sketch/ellipse.png"
+               internal="1">
+        <sketch-2dpoint_selector id="ellipse_center"
+                                 title="Center"
+                                 tooltip="Center coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="ellipse_focus"
+                                 title="Focus"
+                                 tooltip="Focus coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <labelvalue id="ellipse_major_radius"
+                    icon="icons/Sketch/radius.png"
+                    label="Major radius:"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <labelvalue id="ellipse_minor_radius"
+                    icon="icons/Sketch/radius.png"
+                    label="Minor radius:"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    enable_value="enable_by_preferences">
+        </labelvalue>
+        <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+      </feature>
+      <!-- SketchMacroEllipse -->
+      <feature id="SketchMacroEllipse"
+               icon="icons/Sketch/ellipse.png"
+               title="Ellipse"
+               tooltip="Create ellipse">
+        <sketch-2dpoint_selector id="center_point"
+                                 reference_attribute="center_point_ref"
+                                 title="Center point"
+                                 tooltip="Center point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="major_axis_point"
+                                 reference_attribute="major_axis_point_ref"
+                                 title="Major axis point"
+                                 tooltip="Major axis point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences"/>
+        <sketch-2dpoint_selector id="passed_point"
+                                 reference_attribute="passed_point_ref"
+                                 title="Passed point"
+                                 tooltip="Passed point coordinates"
+                                 accept_expressions="0"
+                                 enable_value="enable_by_preferences">
+<!--          <validator id="SketchPlugin_CirclePassedPointValidator"/> -->
+        </sketch-2dpoint_selector>
+<!--        <validator id="GeomValidators_Different" parameters="center_point_ref,passed_point_ref"/> -->
+        <labelvalue id="ellipse_major_radius"
+                    icon="icons/Sketch/radius.png"
+                    label="Major radius:"
+                    tooltip="Set major radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+          <validator id="GeomValidators_Positive"/>
+        </labelvalue>
+        <labelvalue id="ellipse_minor_radius"
+                    icon="icons/Sketch/radius.png"
+                    label="Minor radius:"
+                    tooltip="Set minor radius"
+                    default="computed"
+                    accept_expressions="0"
+                    obligatory="0"
+                    enable_value="enable_by_preferences">
+          <validator id="GeomValidators_Positive"/>
+        </labelvalue>
+        <boolvalue id="Auxiliary"
+                   tooltip="Construction element"
+                   label="Auxiliary"
+                   default="false"
+                   obligatory="0"/>
+      </feature>
+    </group>
+
     <group id="Projection">
       <!-- Intersection Point -->
       <!-- feature