Salome HOME
Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003)
authorazv <azv@opencascade.com>
Tue, 17 Sep 2019 12:57:31 +0000 (15:57 +0300)
committerazv <azv@opencascade.com>
Tue, 17 Sep 2019 13:06:15 +0000 (16:06 +0300)
Testing possibility to remove full ellipse and all its construction elements.

src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp
src/ModelHighAPI/ModelHighAPI_Tools.cpp
src/SketchAPI/SketchAPI_Ellipse.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchPlugin/SketchPlugin_Line.h
src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
src/SketchPlugin/SketchPlugin_MacroEllipse.h
src/SketchPlugin/SketchPlugin_Point.cpp
src/SketchPlugin/SketchPlugin_Point.h
src/SketchPlugin/Test/TestRemoveEllipse.py [new file with mode: 0644]

index 09e944d4ee7995413c522e680eea05f3dbc59060..adba1299442d7961196cb8c66ad60685982a18f3 100644 (file)
@@ -281,6 +281,12 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) {
     std::list<std::string> aResList; // list of resulting strings
     for(std::list<ObjectPtr>::iterator aL = aList.begin(); aL != aList.end(); aL++) {
       if (aL->get()) {
+        if (isSketchFeatures) {
+          // do not control construction features of an ellipse and other
+          FeaturePtr aFeature = ModelAPI_Feature::feature(*aL);
+          if (aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+            continue; // skip internal constraints
+        }
         aResList.push_back((*aL)->data()->name());
       } else if (!isSketchFeatures) {
         aResList.push_back("__empty__");
index 0b6f6fc39c8272a3a8cc86d5cd5fb19a99fe7c1e..c61974d3be3646390916096047a1423b78c73fb4 100644 (file)
@@ -403,6 +403,10 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc,
   std::list<ObjectPtr>::iterator allIter = allObjects.begin();
   for(; allIter != allObjects.end(); allIter++) {
     ObjectPtr anObject = *allIter;
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+    if (aFeature->getKind() == "SketchConstraintCoincidenceInternal")
+      continue; // no need to dump and check internal constraints
+
     if (theCompare) {
       std::map<std::string, ModelHighAPI_FeatureStore>::iterator
         anObjFind = aDocFind->second.find(anObject->data()->name());
@@ -420,7 +424,6 @@ std::string storeFeatures(const std::string& theDocName, DocumentPtr theDoc,
       theStore[theDocName][anObject->data()->name()] = ModelHighAPI_FeatureStore(anObject);
     }
 
-    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
     if (aFeature) {
       // iterate all results of this feature
       std::list<ResultPtr> allResults;
index 7b005014e25f7dd5e027338c9dc18f9b3e33ed3e..b87dc52cb1a1fdaff60a372fe42dc2fb5e3759af 100644 (file)
@@ -177,17 +177,24 @@ static void createInternalConstraint(const CompositeFeaturePtr& theSketch,
 }
 
 static FeaturePtr createPoint(const CompositeFeaturePtr& theSketch,
-                              const AttributePtr& theCoincident,
+                              const FeaturePtr& theEllipse,
+                              const std::string& theCoincident,
                               const std::string& theAuxOrName)
 {
-  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theCoincident);
+  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theEllipse->attribute(theCoincident));
 
   FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
   aCoord->setValue(anElPoint->x(), anElPoint->y());
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
   aPointFeature->execute();
 
+  std::string aName = theEllipse->name() + "_" + theCoincident;
+  aPointFeature->data()->setName(aName);
+  aPointFeature->lastResult()->data()->setName(aName);
+
   if (theAuxOrName == AUXILIARY_VALUE)
     aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
   else if (!theAuxOrName.empty()) {
@@ -201,14 +208,15 @@ static FeaturePtr createPoint(const CompositeFeaturePtr& theSketch,
 }
 
 static FeaturePtr createAxis(const CompositeFeaturePtr& theSketch,
-                             const AttributePtr& theCoincidentStart,
-                             const AttributePtr& theCoincidentEnd,
+                             const FeaturePtr& theEllipse,
+                             const std::string& theCoincidentStart,
+                             const std::string& theCoincidentEnd,
                              const std::string& theAuxOrName)
 {
   AttributePoint2DPtr aStartPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theCoincidentStart);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentStart));
   AttributePoint2DPtr aEndPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theCoincidentEnd);
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentEnd));
 
   FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
@@ -217,10 +225,17 @@ static FeaturePtr createAxis(const CompositeFeaturePtr& theSketch,
   AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aLineFeature->attribute(SketchPlugin_Line::END_ID()));
   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
   aLineFeature->execute();
 
+  std::string aName = theEllipse->name() + "_" +
+      (theCoincidentStart == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ?
+       "major_axis" : "minor_axis");
+  aLineFeature->data()->setName(aName);
+  aLineFeature->lastResult()->data()->setName(aName);
+
   if (theAuxOrName == AUXILIARY_VALUE)
-    aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+    aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(true);
   else if (!theAuxOrName.empty()) {
     aLineFeature->data()->setName(theAuxOrName);
     aLineFeature->lastResult()->data()->setName(theAuxOrName);
@@ -248,42 +263,40 @@ std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Ellipse::construct
 
   std::list<FeaturePtr> anEntities;
   if (!center.empty()) {
-    AttributePtr aCenterAttr = anEllipse->attribute(SketchPlugin_Ellipse::CENTER_ID());
-    anEntities.push_back(createPoint(aSketch, aCenterAttr, center));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::CENTER_ID(), center));
   }
   if (!firstFocus.empty()) {
-    AttributePtr aFocusAttr = anEllipse->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID());
-    anEntities.push_back(createPoint(aSketch, aFocusAttr, firstFocus));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::FIRST_FOCUS_ID(), firstFocus));
   }
   if (!secondFocus.empty()) {
-    AttributePtr aFocusAttr = anEllipse->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID());
-    anEntities.push_back(createPoint(aSketch, aFocusAttr, secondFocus));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::SECOND_FOCUS_ID(), secondFocus));
   }
   if (!majorAxisStart.empty()) {
-    AttributePtr aStartAttr = anEllipse->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
-    anEntities.push_back(createPoint(aSketch, aStartAttr, majorAxisStart));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(), majorAxisStart));
   }
   if (!majorAxisEnd.empty()) {
-    AttributePtr aEndAttr = anEllipse->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
-    anEntities.push_back(createPoint(aSketch, aEndAttr, majorAxisEnd));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(), majorAxisEnd));
   }
   if (!minorAxisStart.empty()) {
-    AttributePtr aStartAttr = anEllipse->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
-    anEntities.push_back(createPoint(aSketch, aStartAttr, minorAxisStart));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::MINOR_AXIS_START_ID(), minorAxisStart));
   }
   if (!minorAxisEnd.empty()) {
-    AttributePtr aEndAttr = anEllipse->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
-    anEntities.push_back(createPoint(aSketch, aEndAttr, minorAxisEnd));
+    anEntities.push_back(
+        createPoint(aSketch, anEllipse, SketchPlugin_Ellipse::MINOR_AXIS_END_ID(), minorAxisEnd));
   }
   if (!majorAxis.empty()) {
-    AttributePtr aStartAttr = anEllipse->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
-    AttributePtr aEndAttr = anEllipse->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
-    anEntities.push_back(createAxis(aSketch, aStartAttr, aEndAttr, majorAxis));
+    anEntities.push_back(createAxis(aSketch, anEllipse, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+                                    SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(), majorAxis));
   }
   if (!minorAxis.empty()) {
-    AttributePtr aStartAttr = anEllipse->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
-    AttributePtr aEndAttr = anEllipse->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
-    anEntities.push_back(createAxis(aSketch, aStartAttr, aEndAttr, minorAxis));
+    anEntities.push_back(createAxis(aSketch, anEllipse, SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+                                    SketchPlugin_Ellipse::MINOR_AXIS_END_ID(), minorAxis));
   }
 
   return SketchAPI_SketchEntity::wrap(anEntities);
index 80b68f571b84ce5344145f19247a4d3133f4fea6..b7074675bcdd3850cc46d5bbe83ec13f3d4b3910 100644 (file)
@@ -263,6 +263,7 @@ ADD_UNIT_TESTS(
   TestProjectionIntoResult.py
   TestProjectionUpdate.py
   TestRectangle.py
+  TestRemoveEllipse.py
   TestRemoveSketch.py
   TestSignedDistancePointLine.py
   TestSignedDistancePointPoint.py
index f01a332f296b0b90d751165547938b937376df3f..e5284719311c0f2beed9b62948160717992e536f 100644 (file)
@@ -47,6 +47,9 @@ void SketchPlugin_Line::initAttributes()
   /// new attributes should be added to end of the feature in order to provide
   /// correct attribute values in previous saved studies
   data()->addAttribute(LENGTH_ID(), ModelAPI_AttributeDouble::typeId());
+
+  data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
 }
 
 void SketchPlugin_Line::initDerivedClassAttributes()
index 7a23944ae6260d0ab8714a83579e07ea033e931a..73ad4310799662ccbf1bee3177ee8a018e7a3fb9 100644 (file)
@@ -63,6 +63,13 @@ class SketchPlugin_Line : public SketchPlugin_SketchEntity,
     return MY_LENGTH;
   }
 
+  /// Reference to the parent feature
+  inline static const std::string& PARENT_ID()
+  {
+    static const std::string& MY_PARENT_ID("ParentFeature");
+    return MY_PARENT_ID;
+  }
+
   /// Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind();
 
index fc6e034535bc92a5f12850dfb33a881dd133c61c..99910cebaf0704d4b6cc90c00a518b39005a0535 100644 (file)
@@ -295,44 +295,58 @@ FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
   aEllipseFeature->execute();
 
   // create auxiliary points
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()));
-  createAuxiliaryPoint(aEllipseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()));
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
+  createAuxiliaryPoint(aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
   // create auxiliary axes
-  createAuxiliaryAxis(aEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
-                      aEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
-  createAuxiliaryAxis(aEllipseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
-                      aEllipseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()));
+  createAuxiliaryAxis(aEllipseFeature,
+                      SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
+                      SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
+  createAuxiliaryAxis(aEllipseFeature,
+                      SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
+                      SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
 
   return aEllipseFeature;
 }
 
-void SketchPlugin_MacroEllipse::createAuxiliaryPoint(const AttributePtr& theEllipsePoint)
+void SketchPlugin_MacroEllipse::createAuxiliaryPoint(const FeaturePtr& theEllipseFeature,
+                                                     const std::string& theEllipsePoint)
 {
   FeaturePtr aPointFeature = sketch()->addFeature(SketchPlugin_Point::ID());
   aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
 
-  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipsePoint);
+  AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theEllipseFeature->attribute(theEllipsePoint));
 
   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
   aCoord->setValue(anElPoint->x(), anElPoint->y());
 
+  aPointFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
+  aPointFeature->data()->setName(aName);
+  aPointFeature->lastResult()->data()->setName(aName);
+
   createInternalConstraint(anElPoint, aCoord);
 }
 
-void SketchPlugin_MacroEllipse::createAuxiliaryAxis(const AttributePtr& theStartPoint,
-                                                    const AttributePtr& theEndPoint)
+void SketchPlugin_MacroEllipse::createAuxiliaryAxis(const FeaturePtr& theEllipseFeature,
+                                                    const std::string& theStartPoint,
+                                                    const std::string& theEndPoint)
 {
   FeaturePtr aLineFeature = sketch()->addFeature(SketchPlugin_Line::ID());
   aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
 
-  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theStartPoint);
-  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEndPoint);
+  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theEllipseFeature->attribute(theStartPoint));
+  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theEllipseFeature->attribute(theEndPoint));
 
   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aLineFeature->attribute(SketchPlugin_Line::START_ID()));
@@ -342,6 +356,12 @@ void SketchPlugin_MacroEllipse::createAuxiliaryAxis(const AttributePtr& theStart
       aLineFeature->attribute(SketchPlugin_Line::END_ID()));
   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
 
+  aLineFeature->execute();
+  std::string aName = theEllipseFeature->name() + "_" +
+      (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
+  aLineFeature->data()->setName(aName);
+  aLineFeature->lastResult()->data()->setName(aName);
+
   createInternalConstraint(aStartPoint, aLineStart);
   createInternalConstraint(aEndPoint, aLineEnd);
 }
index 2b92f7f2aad55a8b81abc0b590e2f22ca8cb2388..4bea22221d0ad0aa44f24c9aa6d7ed403caea2c4 100644 (file)
@@ -162,8 +162,11 @@ private:
 
   FeaturePtr createEllipseFeature();
 
-  void createAuxiliaryPoint(const AttributePtr& theEllipsePoint);
-  void createAuxiliaryAxis(const AttributePtr& theStartPoint, const AttributePtr& theEndPoint);
+  void createAuxiliaryPoint(const FeaturePtr& theEllipseFeature,
+                            const std::string& theEllipsePoint);
+  void createAuxiliaryAxis(const FeaturePtr& theEllipseFeature,
+                           const std::string& theStartPoint,
+                           const std::string& theEndPoint);
 
   void createInternalConstraint(const AttributePtr& thePoint1, const AttributePtr& thePoint2);
 
index c53006489726c728a5ac5c6877c996b4b90cc6dd..9a6358053132ae4e99bf59bebef0c80de454c46b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <ModelAPI_Data.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_AttributeReference.h>
 #include <ModelAPI_AttributeSelection.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
@@ -41,6 +42,9 @@ void SketchPlugin_Point::initDerivedClassAttributes()
   data()->addAttribute(SketchPlugin_Point::COORD_ID(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+
+  data()->addAttribute(PARENT_ID(), ModelAPI_AttributeReference::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PARENT_ID());
 }
 
 void SketchPlugin_Point::execute()
index 1cdcae05f39ddb505170bedc42e94cb4fe169a23..5111ce0a8922e0e8f47d5a373b89f054efbbfd48 100644 (file)
@@ -44,6 +44,12 @@ class SketchPlugin_Point : public SketchPlugin_SketchEntity
     static const std::string MY_COORD_ID("PointCoordinates");
     return MY_COORD_ID;
   }
+  /// Reference to the parent feature
+  inline static const std::string& PARENT_ID()
+  {
+    static const std::string& MY_PARENT_ID("ParentFeature");
+    return MY_PARENT_ID;
+  }
   /// Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
   {
diff --git a/src/SketchPlugin/Test/TestRemoveEllipse.py b/src/SketchPlugin/Test/TestRemoveEllipse.py
new file mode 100644 (file)
index 0000000..7a8d3c4
--- /dev/null
@@ -0,0 +1,106 @@
+# 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 ellipse and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbEllipses, theNbInternalConstraints):
+    model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+    model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+    model.testNbSubFeatures(theSketch, "SketchEllipse", theNbEllipses)
+    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"))
+SketchEllipse_1 = Sketch_1.addEllipse(40, 30, 70, 40, 20)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipse_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 = 5
+DEFAULT_POINTS = 7
+DEFAULT_LINES = 2
+DEFAULT_ELLIPSES = 1
+DEAFULT_INTERNALS = 11
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, 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_ELLIPSES, DEAFULT_INTERNALS - 1)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, 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_ELLIPSES, DEAFULT_INTERNALS - 2)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+    model.undo()
+    assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_ELLIPSES, DEAFULT_INTERNALS)
+    assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3.  Remove the ellipse.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchEllipse_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_ELLIPSES, 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"))
+SketchEllipse_2 = Sketch_2.addEllipse(40, -30, 70, 0, 10)
+[Center, Focus1, Focus2, MajorAxisStart, MajorAxisEnd, MinorAxisStart, MinorAxisEnd, MajorAxisLine, MinorAxisLine] = SketchEllipse_2.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+model.end()
+
+model.begin()
+removeFeaturesAndReferences(FeatureSet([MajorAxisLine.feature(), Focus2.feature()]))
+Focus1.setAuxiliary(False)
+MinorAxisEnd.setAuxiliary(False)
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_ELLIPSES, DEAFULT_INTERNALS - 3)
+assert(model.dof(Sketch_2) == DEFAULT_DOF)
+
+assert(model.checkPythonDump())