Salome HOME
Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003)
authorazv <azv@opencascade.com>
Wed, 2 Oct 2019 10:55:32 +0000 (13:55 +0300)
committerazv <azv@opencascade.com>
Wed, 2 Oct 2019 12:28:29 +0000 (15:28 +0300)
Unit tests for creation and destruction of elliptic arcs.

src/SketchAPI/SketchAPI_EllipticArc.cpp
src/SketchAPI/SketchAPI_MacroEllipse.cpp
src/SketchAPI/SketchAPI_MacroEllipse.h
src/SketchAPI/SketchAPI_MacroEllipticArc.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_EllipticArc.cpp
src/SketchPlugin/Test/TestCreateEllipticArc.py [new file with mode: 0644]
src/SketchPlugin/Test/TestCreateEllipticArcByExternal.py [new file with mode: 0644]
src/SketchPlugin/Test/TestRemoveEllipticArc.py [new file with mode: 0644]

index 27275096ce533c3f29ffd82ee96951b2d689ddd9..a3e39a2b65147ab1f21c4fd5f3d20974162e1aea 100644 (file)
@@ -92,11 +92,12 @@ void SketchAPI_EllipticArc::setByCenterFocusAndPoints(double theCenterX, double
                                                       double theEndX, double theEndY,
                                                       bool theInversed)
 {
-  fillAttribute(center(), theCenterX, theCenterY);
-  fillAttribute(firstFocus(), theFocusX, theFocusY);
-  fillAttribute(startPoint(), theStartX, theStartY);
-  fillAttribute(endPoint(), theEndX, theEndY);
+  // the order of attribute initialization is reversed to avoid odd recalculation of an elliptic arc
   fillAttribute(theInversed, reversed());
+  fillAttribute(endPoint(), theEndX, theEndY);
+  fillAttribute(startPoint(), theStartX, theStartY);
+  fillAttribute(firstFocus(), theFocusX, theFocusY);
+  fillAttribute(center(), theCenterX, theCenterY);
 
   execute();
 }
@@ -108,11 +109,12 @@ void SketchAPI_EllipticArc::setByCenterFocusAndPoints(
     const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
     bool theInversed)
 {
-  fillAttribute(theCenter, center());
-  fillAttribute(theFocus, firstFocus());
-  fillAttribute(theStart, startPoint());
-  fillAttribute(theEnd, endPoint());
+  // the order of attribute initialization is reversed to avoid odd recalculation of an elliptic arc
   fillAttribute(theInversed, reversed());
+  fillAttribute(theEnd, endPoint());
+  fillAttribute(theStart, startPoint());
+  fillAttribute(theFocus, firstFocus());
+  fillAttribute(theCenter, center());
 
   execute();
 }
index 3a4ef16d3631b4191c670a57d20d7d3bc4988ccb..e833775e204e281e037e7eb4a0e1486f0439d681 100644 (file)
@@ -56,10 +56,11 @@ static CompositeFeaturePtr sketch(FeaturePtr theFeature)
 }
 
 
-SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+SketchAPI_MacroEllipse::SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                               bool callInitialize)
 : SketchAPI_SketchEntity(theFeature)
 {
-  if (initialize())
+  if (callInitialize && initialize())
     mySketch = sketch(theFeature);
 }
 
index 596a417e6801682a5479a8e84354f355541d62f8..7e0103b16b7057ee2d6ff4229c9430bcd9bf567b 100644 (file)
@@ -37,7 +37,8 @@ class SketchAPI_MacroEllipse: public SketchAPI_SketchEntity
 public:
   /// Constructor without values.
   SKETCHAPI_EXPORT
-  explicit SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+  explicit SketchAPI_MacroEllipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                  bool callInitialize = true);
 
   /// Constructor with values.
   SKETCHAPI_EXPORT
index bde81dfef0f16f4d10b5d94afa042dbf7d325d11..f76f797c5aec8274bb6a7e5e323a830c337a7bfe 100644 (file)
@@ -59,7 +59,7 @@ static void fillAttribute(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
 }
 
 SketchAPI_MacroEllipticArc::SketchAPI_MacroEllipticArc(const FeaturePtr& theFeature)
-  : SketchAPI_MacroEllipse(theFeature)
+  : SketchAPI_MacroEllipse(theFeature, false)
 {
 }
 
@@ -74,7 +74,7 @@ SketchAPI_MacroEllipticArc::SketchAPI_MacroEllipticArc(
     const std::shared_ptr<GeomAPI_Pnt2d>&    theArcEnd,
     const ModelHighAPI_RefAttr&              theArcEndRef,
     const bool                               theReversed)
-  : SketchAPI_MacroEllipse(theFeature)
+  : SketchAPI_MacroEllipse(theFeature, false)
 {
   if (initialize()) {
     fillAttribute(theCenter, theCenterRef,
index cfcf93b7b7c3554a4e557ecb2b35d1b28244349c..0504e411d9daccf4e2251f6d8ce4e63faaf879a8 100644 (file)
@@ -662,19 +662,6 @@ std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
       theInversed));
 }
 
-std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
-    const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-    const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
-    const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
-    const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-    bool theInversed)
-{
-  std::shared_ptr<ModelAPI_Feature> aFeature =
-      compositeFeature()->addFeature(SketchPlugin_EllipticArc::ID());
-  return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature,
-      theCenter, theFocus, theStart, theEnd, theInversed));
-}
-
 std::shared_ptr<SketchAPI_MacroEllipticArc> SketchAPI_Sketch::addEllipticArc(
     const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
     const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
index 2f722b5e5ae053ade63b6d2ea2daf45c21682433..a6ce997207990eed4572ad8ec1110b5d09385546 100644 (file)
@@ -311,14 +311,6 @@ public:
       bool theInversed = false);
   /// Add elliptic arc
   SKETCHAPI_EXPORT
-  std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(
-      const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
-      const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
-      const std::shared_ptr<GeomAPI_Pnt2d>& theStart,
-      const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
-      bool theInversed = false);
-  /// Add elliptic arc
-  SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroEllipticArc> addEllipticArc(
       const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
       const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
index 2d4693a75e0c57b3d29ee7d87099248a99102e42..d21085a97d7205ab12fc8795507e921ae69d51b5 100644 (file)
@@ -245,6 +245,8 @@ ADD_UNIT_TESTS(
   TestCreateEllipseByCenterSemiaxisAndPassed.py
   TestCreateEllipseByMajorAxisAndPassed.py
   TestCreateEllipseByExternal.py
+  TestCreateEllipticArc.py
+  TestCreateEllipticArcByExternal.py
   TestDegeneratedGeometry.py
   TestDistanceDump.py
   TestDistanceSignedVsUnsigned01.py
@@ -277,6 +279,7 @@ ADD_UNIT_TESTS(
   TestProjectionUpdate.py
   TestRectangle.py
   TestRemoveEllipse.py
+  TestRemoveEllipticArc.py
   TestRemoveSketch.py
   TestSignedDistancePointLine.py
   TestSignedDistancePointPoint.py
index 1c56d27e9f6b72085b1d9405d80c3d87a22f45ee..5b8b109e0da138311ee30446dd82cd4d8032abe6 100644 (file)
@@ -110,6 +110,7 @@ void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) {
       std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
       std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
 
+      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
       aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
@@ -128,11 +129,27 @@ void SketchPlugin_EllipticArc::attributeChanged(const std::string& theID) {
 
       real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
       real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+
+      double aStartParam, aMidParam, aEndParam;
+      anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+      anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+      anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+      if (aEndParam < aStartParam)
+        aEndParam += 2.0 * PI;
+      if (aMidParam < aStartParam)
+        aMidParam += 2.0 * PI;
+      boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+
+      data()->blockSendAttributeUpdated(aWasBlocked, false);
+
+      fillCharacteristicPoints();
     }
   }
   else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() ||
            theID == START_POINT_ID() || theID == END_POINT_ID())
     fillCharacteristicPoints();
+  else if (theID == REVERSED_ID() && myParamDelta == 0.0)
+    myParamDelta = 2.0 * PI;
 }
 
 static void calculateRadii(const GeomPnt2dPtr& theCenter,
@@ -152,29 +169,30 @@ static void calculateRadii(const GeomPnt2dPtr& theCenter,
 bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
 {
   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
   std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(FIRST_FOCUS_ID()));
   std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_POINT_ID()));
   std::shared_ptr<GeomDataAPI_Point2D> aEndPointAttr =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
 
   if (!aCenterAttr->isInitialized() ||
-    !aFocusAttr->isInitialized() ||
-    !aStartPointAttr->isInitialized()) {
+      !aFocusAttr->isInitialized() ||
+      !aStartPointAttr->isInitialized()) {
     return false;
   }
 
-  data()->blockSendAttributeUpdated(true);
   GeomPnt2dPtr aCenter2d = aCenterAttr->pnt();
   GeomPnt2dPtr aFocus2d = aFocusAttr->pnt();
   GeomPnt2dPtr aStart2d = aStartPointAttr->pnt();
 
   double aMajorRadius = 0.0, aMinorRadius = 0.0;
   calculateRadii(aCenter2d, aFocus2d, aStart2d, aMajorRadius, aMinorRadius);
-  if (aMinorRadius < tolerance *aMajorRadius)
+  if (aMinorRadius < tolerance * aMajorRadius)
     return false;
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
   real(MAJOR_RADIUS_ID())->setValue(aMajorRadius);
   real(MINOR_RADIUS_ID())->setValue(aMinorRadius);
 
@@ -186,16 +204,16 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
     ->setValue(2.0 * aCenter2d->x() - aFocus2d->x(), 2.0 * aCenter2d->y() - aFocus2d->y());
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_START_ID()))
     ->setValue(aCenter2d->x() - aMajorDir2d->x() * aMajorRadius,
-      aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
+               aCenter2d->y() - aMajorDir2d->y() * aMajorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MAJOR_AXIS_END_ID()))
     ->setValue(aCenter2d->x() + aMajorDir2d->x() * aMajorRadius,
-      aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
+               aCenter2d->y() + aMajorDir2d->y() * aMajorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_START_ID()))
     ->setValue(aCenter2d->x() - aMinorDir2d->x() * aMinorRadius,
-      aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
+               aCenter2d->y() - aMinorDir2d->y() * aMinorRadius);
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(MINOR_AXIS_END_ID()))
     ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
-      aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
+               aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
 
   if (aEndPointAttr->isInitialized()) {
     // recalculate REVERSED flag
@@ -211,17 +229,17 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
       aParamEnd -= aParamStart;
 
       if (myParamDelta >= 0.0 && myParamDelta <= PI * 0.5 &&
-          aParamEnd < 0 && aParamEnd >= -PI * 0.5) {
+          aParamEnd < 0.0 && aParamEnd >= -PI * 0.5) {
         boolean(REVERSED_ID())->setValue(true);
       }
       else if (myParamDelta <= 0.0 && myParamDelta >= -PI * 0.5 &&
                aParamEnd > 0.0 && aParamEnd <= PI * 0.5) {
         boolean(REVERSED_ID())->setValue(false);
       }
+      myParamDelta = aParamEnd;
     }
-    myParamDelta = aParamEnd;
   }
-  data()->blockSendAttributeUpdated(false);
+  data()->blockSendAttributeUpdated(aWasBlocked, false);
 
   return true;
 }
diff --git a/src/SketchPlugin/Test/TestCreateEllipticArc.py b/src/SketchPlugin/Test/TestCreateEllipticArc.py
new file mode 100644 (file)
index 0000000..fe675da
--- /dev/null
@@ -0,0 +1,379 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+    Test creation of elliptic arc by center, semi-axis, start and end points
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-01"
+
+class TestEllipticArc(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myCenter = GeomAPI_Pnt2d(50., 50.)
+    self.myFocus = GeomAPI_Pnt2d(70., 60.)
+    self.myStartPoint = GeomAPI_Pnt2d(60., 65.)
+    self.myEndPoint = GeomAPI_Pnt2d(60., 42.535751)
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+  def checkPointOnLine(self, theCoordinates, theLine):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointLine(point, theLine)
+    self.assertAlmostEqual(dist, 0, 7)
+
+  def checkPointOnCircle(self, theCoordinates, theCircle):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    dist = model.distancePointPoint(point, theCircle.center())
+    self.assertAlmostEqual(dist , theCircle.radius().value(), 7)
+
+  def checkPointOnEllipse(self, theCoordinates, theEllipse):
+    point = GeomAPI_Pnt2d(theCoordinates.x(), theCoordinates.y())
+    firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
+    distPF1 = model.distancePointPoint(firstFocus2d,  point)
+    secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
+    distPF2 = model.distancePointPoint(secondFocus2d,  point)
+    if issubclass(type(theEllipse), SketchAPI_Ellipse):
+      majorRad = theEllipse.majorRadius().value()
+    else:
+      majorRad = theEllipse.majorRadius()
+    self.assertAlmostEqual(distPF1 + distPF2, 2.0 * majorRad, 7)
+
+
+  def test_elliptic_arc_by_coordinates(self):
+    """ Test 1. Create elliptic arc by coordinates of center, point on the major axis, start and end points
+    """
+    self.myEllipse1 = self.mySketch.addEllipticArc(self.myCenter.x(), self.myCenter.y(),
+                                                   self.myFocus.x(), self.myFocus.y(),
+                                                   self.myStartPoint.x(), self.myStartPoint.y(),
+                                                   self.myEndPoint.x(), self.myEndPoint.y(), False)
+    self.myDOF += 7
+
+    self.myEllipse2 = self.mySketch.addEllipticArc(self.myCenter.x(), self.myCenter.y(),
+                                                   self.myFocus.x(), self.myFocus.y(),
+                                                   self.myStartPoint.x(), self.myStartPoint.y(),
+                                                   self.myEndPoint.x(), self.myEndPoint.y(), True)
+    self.myDOF += 7
+    model.do()
+
+    # check both ellipses are equal
+    anArcEdge1 = self.myEllipse1.defaultResult().shape().edge()
+    anArcEdge2 = self.myEllipse2.defaultResult().shape().edge()
+    anEllipse1 = anArcEdge1.ellipse()
+    anEllipse2 = anArcEdge2.ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    self.checkPointsEqual(self.myEllipse1.startPoint(), self.myEllipse2.startPoint())
+    self.checkPointsEqual(self.myEllipse1.endPoint(), self.myEllipse2.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 2)
+    # check middle points are different
+    assert(anArcEdge1.middlePoint().x() < self.myStartPoint.x())
+    assert(anArcEdge2.middlePoint().x() > self.myStartPoint.x())
+
+  def test_elliptic_arc_by_points(self):
+    """ Test 2. Create elliptic arc by points
+    """
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 7
+    model.do()
+    anEllipseFeature1 = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature1)
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 7
+    model.do()
+    anEllipseFeature2 = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse2 = SketchAPI_EllipticArc(anEllipseFeature2)
+
+    # check both ellipses are equal
+    anArcEdge1 = anEllipseFeature1.lastResult().shape().edge()
+    anArcEdge2 = anEllipseFeature2.lastResult().shape().edge()
+    anEllipse1 = anArcEdge1.ellipse()
+    anEllipse2 = anArcEdge2.ellipse()
+    self.checkPointsEqual(anEllipse1.center(), anEllipse2.center())
+    self.checkPointsEqual(anEllipse1.firstFocus(), anEllipse2.firstFocus())
+    self.checkPointsEqual(anEllipse1.secondFocus(), anEllipse2.secondFocus())
+    self.assertAlmostEqual(anEllipse1.minorRadius(), anEllipse2.minorRadius())
+    self.assertAlmostEqual(anEllipse1.majorRadius(), anEllipse2.majorRadius())
+    self.checkPointsEqual(self.myEllipse1.startPoint(), self.myEllipse2.startPoint())
+    self.checkPointsEqual(self.myEllipse1.endPoint(), self.myEllipse2.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 14)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 4)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 2)
+    # check middle points are different
+    assert(anArcEdge1.middlePoint().x() < self.myStartPoint.x())
+    assert(anArcEdge2.middlePoint().x() > self.myStartPoint.x())
+
+  def test_elliptic_arc_with_fixed_center(self):
+    """ Test 3. Create elliptic arc which center is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(aLine.endPoint(), self.myFocus, self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointsEqual(anEllipse.center(), aLine.endPoint())
+    self.checkPointOnEllipse(self.myStartPoint, anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_line(self):
+    """ Test 4. Create elliptic arc which center is coincident with a line
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, aLine.result()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on line
+    self.checkPointOnLine(anEllipse.center(), aLine)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_circle(self):
+    """ Test 5. Create elliptic arc which center is coincident with a circle
+    """
+    aCircle = self.mySketch.addCircle(10, 10, 20)
+    self.myDOF += 3
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, aCircle.defaultResult()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on circle
+    self.checkPointOnCircle(anEllipse.center(), aCircle)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchCircle", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_center_on_ellipse(self):
+    """ Test 6. Create elliptic arc which center is coincident with another ellipse
+    """
+    anOtherEllipse = self.mySketch.addEllipse(10, 10, 30, 20, 10)
+    self.myDOF += 5
+    model.do()
+
+    self.mySketch.addEllipticArc([self.myCenter, anOtherEllipse.defaultResult()], self.myFocus, self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    # check center on ellipse
+    self.checkPointOnEllipse(anEllipse.center(), anOtherEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.startPoint(), anEllipse)
+    self.checkPointOnEllipse(self.myEllipse1.endPoint(), anEllipse)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 2)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_fixed_axis(self):
+    """ Test 7. Create elliptic arc which point on major semi-axis is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, aLine.endPoint(), self.myStartPoint, self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(self.myStartPoint, anEllipse)
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    # check distance is equal to major semi-axis
+    dist = model.distancePointPoint(GeomAPI_Pnt2d(anEllipse.center().x(), anEllipse.center().y()), aLine.endPoint())
+    self.assertAlmostEqual(dist, anEllipse.majorRadius(), 7)
+    self.checkPointsEqual(self.myEllipse1.majorAxisPositive(), aLine.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_axis_on_line(self):
+    """ Test 8. Create elliptic arc which point on major semi-axis is coincident with a line.
+                Check no coincidence constraint is created.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, [self.myFocus, aLine.result()], self.myStartPoint, self.myEndPoint, True)
+    self.myDOF += 7
+    model.do()
+
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 0)
+
+  def test_elliptic_arc_with_fixed_start_point(self):
+    """ Test 9. Create elliptic arc which start point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, aLine.endPoint(), self.myEndPoint, True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    self.checkPointsEqual(aLine.endPoint(), self.myEllipse1.startPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_start_point_on_line(self):
+    """ Test 10. Create elliptic arc which start point is placed on a line.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, [self.myStartPoint, aLine.result()], self.myEndPoint, False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnLine(self.myEllipse1.startPoint(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_fixed_end_point(self):
+    """ Test 11. Create elliptic arc which end point is coincident with another point
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, aLine.endPoint(), True)
+    self.myDOF += 5
+    model.do()
+    # check ellipse
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnEllipse(aLine.endPoint(), anEllipse)
+    self.checkPointsEqual(aLine.endPoint(), self.myEllipse1.endPoint())
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+  def test_elliptic_arc_with_end_point_on_line(self):
+    """ Test 12. Create elliptic arc which end point is placed on a line.
+    """
+    aLine = self.mySketch.addLine(10, 10, 30, 40)
+    self.myDOF += 4
+    model.do()
+
+    self.mySketch.addEllipticArc(self.myCenter, self.myFocus, self.myStartPoint, [self.myEndPoint, aLine.result()], False)
+    self.myDOF += 6
+    model.do()
+
+    anEllipseFeature = model.lastSubFeature(self.mySketch, "SketchEllipticArc")
+    self.myEllipse1 = SketchAPI_EllipticArc(anEllipseFeature)
+    anEllipse = anEllipseFeature.lastResult().shape().edge().ellipse()
+    self.checkPointOnLine(self.myEllipse1.endPoint(), aLine)
+    # check number of features
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", 7)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
+    model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", 1)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", 1)
+
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
diff --git a/src/SketchPlugin/Test/TestCreateEllipticArcByExternal.py b/src/SketchPlugin/Test/TestCreateEllipticArcByExternal.py
new file mode 100644 (file)
index 0000000..7d83217
--- /dev/null
@@ -0,0 +1,142 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+    Test creation of elliptic arc by external feature
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-10-02"
+
+# reference data
+CENTER_POINT = GeomAPI_Pnt2d(50., 50.)
+MAJOR_AXIS_POINT = GeomAPI_Pnt2d(70., 60.)
+START_POINT = GeomAPI_Pnt2d(60., 65.)
+END_POINT = GeomAPI_Pnt2d(60., 42.535751)
+ARC_LENGTH_1 = 0
+ARC_LENGTH_2 = 0
+
+class TestEllipticArcByExternal(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myDOF = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+  def checkPointsEqual(self, thePoint1, thePoint2):
+    self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), 5)
+    self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), 5)
+
+
+  def test_elliptic_arc_by_external_name_1(self):
+    """ Test 1. Create elliptic arc by name of external edge (direct)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc("Sketch_1/SketchEllipticArc_1")
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), START_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), END_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_1)
+
+  def test_elliptic_arc_by_external_name_2(self):
+    """ Test 2. Create elliptic arc by name of external edge (reversed)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc("Sketch_1/SketchEllipticArc_2")
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(anArcEdge.firstPoint(), END_POINT)
+    self.checkPointsEqual(anArcEdge.lastPoint(), START_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_2)
+
+  def test_elliptic_arc_by_external_selection_1(self):
+    """ Test 3. Create elliptic arc by selected edge (direct)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc(ELLIPTIC_ARC_1.results()[-1])
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), START_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), END_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_1)
+
+  def test_elliptic_arc_by_external_selection_2(self):
+    """ Test 4. Create elliptic arc by selected edge (reversed)
+    """
+    self.myEllipse = self.mySketch.addEllipticArc(ELLIPTIC_ARC_2.results()[-1])
+    model.do()
+
+    # check ellipse parameters
+    anArcEdge = self.myEllipse.defaultResult().shape().edge()
+    anEllipse = anArcEdge.ellipse()
+    self.checkPointsEqual(anEllipse.center(), CENTER_POINT)
+    self.checkPointsEqual(self.myEllipse.majorAxisPositive(), MAJOR_AXIS_POINT)
+    self.checkPointsEqual(self.myEllipse.startPoint(), END_POINT)
+    self.checkPointsEqual(self.myEllipse.endPoint(), START_POINT)
+    self.assertAlmostEqual(anArcEdge.length(), ARC_LENGTH_2)
+
+
+if __name__ == "__main__":
+    model.begin()
+    aDocument = model.moduleDocument()
+    aSketch = model.addSketch(aDocument, model.defaultPlane("XOY"))
+    aSketch.addEllipticArc(CENTER_POINT, MAJOR_AXIS_POINT, START_POINT, END_POINT, False)
+    model.do()
+
+    ELLIPTIC_ARC_1 = SketchAPI_EllipticArc(model.lastSubFeature(aSketch, "SketchEllipticArc"))
+    ARC_LENGTH_1 = ELLIPTIC_ARC_1.defaultResult().shape().edge().length()
+
+    aSketch.addEllipticArc(CENTER_POINT, MAJOR_AXIS_POINT, START_POINT, END_POINT, True)
+    model.end()
+
+    ELLIPTIC_ARC_2 = SketchAPI_EllipticArc(model.lastSubFeature(aSketch, "SketchEllipticArc"))
+    ARC_LENGTH_2 = ELLIPTIC_ARC_2.defaultResult().shape().edge().length()
+
+    # redefine end point
+    END_POINT = ELLIPTIC_ARC_2.endPoint()
+
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()
diff --git a/src/SketchPlugin/Test/TestRemoveEllipticArc.py b/src/SketchPlugin/Test/TestRemoveEllipticArc.py
new file mode 100644 (file)
index 0000000..ccea403
--- /dev/null
@@ -0,0 +1,107 @@
+# Copyright (C) 2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+    Test removing elliptic arc and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbEllipticArcs, theNbInternalConstraints):
+    model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+    model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+    model.testNbSubFeatures(theSketch, "SketchEllipticArc", theNbEllipticArcs)
+    model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipticArc_1 = Sketch_1.addEllipticArc(40, 30, 70, 60, 60, 65, 60., 23.3257583582, False)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipticArc_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
+
+DEFAULT_DOF = 7
+DEFAULT_POINTS = 7
+DEFAULT_LINES = 2
+DEFAULT_ELLIPTIC_ARCS = 1
+DEAFULT_INTERNALS = 11
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+points = [Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd]
+for pnt in points:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 1)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary axes one by one.
+lines = [MajorAxisLine, MinorAxisLine]
+for ln in lines:
+    model.begin()
+    removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+    model.end()
+
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 2)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3.  Remove the elliptic arc.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchEllipticArc_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchEllipticArc_2 = Sketch_2.addEllipticArc(40, -30, 70, 0, 30, 10, 0, -20, True)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipticArc_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+SketchEllipticArc_2.setAuxiliary(True)
+model.do()
+model.end()
+
+model.begin()
+removeFeaturesAndReferences(FeatureSet([MajorAxisLine.feature(), Focus2.feature()]))
+Focus1.setAuxiliary(False)
+MinorAxisLine.setAuxiliary(False)
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_ELLIPTIC_ARCS, DEAFULT_INTERNALS - 3)
+assert(model.dof(Sketch_2) == DEFAULT_DOF)
+
+assert(model.checkPythonDump())