Salome HOME
Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003)
authorazv <azv@opencascade.com>
Mon, 30 Sep 2019 10:38:02 +0000 (13:38 +0300)
committerazv <azv@opencascade.com>
Mon, 30 Sep 2019 10:38:34 +0000 (13:38 +0300)
Split and Trim features for ellipse and elliptic arc.

src/SketchPlugin/SketchPlugin_EllipticArc.cpp
src/SketchPlugin/SketchPlugin_Split.cpp
src/SketchPlugin/SketchPlugin_Split.h
src/SketchPlugin/SketchPlugin_Tools.cpp
src/SketchPlugin/SketchPlugin_Tools.h
src/SketchPlugin/SketchPlugin_Trim.cpp
src/SketchPlugin/SketchPlugin_Trim.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp

index a5c2b29fb413945892f1afeb32959e474ce94bb3..1c56d27e9f6b72085b1d9405d80c3d87a22f45ee 100644 (file)
@@ -145,13 +145,8 @@ static void calculateRadii(const GeomPnt2dPtr& theCenter,
       theCenter->xy()->multiplied(2.0)->decreased(theFocus->xy())));
   theMajorRadius = 0.5 * (thePassed->distance(theFocus) + thePassed->distance(aSecondFocus));
 
-  GeomDir2dPtr aXAxis(new GeomAPI_Dir2d(theFocus->x() - theCenter->x(),
-                                        theFocus->y() - theCenter->y()));
-  std::shared_ptr<GeomAPI_XY> aPassedVec = thePassed->xy()->decreased(theCenter->xy());
-
-  double x = aPassedVec->dot(aXAxis->xy()) / theMajorRadius;
-  double y = abs(aPassedVec->cross(aXAxis->xy()));
-  theMinorRadius = y / sqrt(1.0 - x * x);
+  double aFocalDist = theCenter->distance(theFocus);
+  theMinorRadius = sqrt(theMajorRadius * theMajorRadius - aFocalDist * aFocalDist);
 }
 
 bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
@@ -162,6 +157,8 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
     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::shared_ptr<GeomDataAPI_Point2D> aEndPointAttr =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
 
   if (!aCenterAttr->isInitialized() ||
     !aFocusAttr->isInitialized() ||
@@ -176,7 +173,7 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
 
   double aMajorRadius = 0.0, aMinorRadius = 0.0;
   calculateRadii(aCenter2d, aFocus2d, aStart2d, aMajorRadius, aMinorRadius);
-  if (aMinorRadius < tolerance)
+  if (aMinorRadius < tolerance *aMajorRadius)
     return false;
   real(MAJOR_RADIUS_ID())->setValue(aMajorRadius);
   real(MINOR_RADIUS_ID())->setValue(aMinorRadius);
@@ -200,8 +197,6 @@ bool SketchPlugin_EllipticArc::fillCharacteristicPoints()
     ->setValue(aCenter2d->x() + aMinorDir2d->x() * aMinorRadius,
       aCenter2d->y() + aMinorDir2d->y() * aMinorRadius);
 
-  std::shared_ptr<GeomDataAPI_Point2D> aEndPointAttr =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_POINT_ID()));
   if (aEndPointAttr->isInitialized()) {
     // recalculate REVERSED flag
     std::shared_ptr<GeomAPI_Ellipse2d> anEllipseForArc(
index 8a07349df82aced06c5caa8590b7f5ccd40eeaa8..a8f054eb8eb5b5948606ac09f3fde632c5f2ab8b 100644 (file)
@@ -43,6 +43,7 @@
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMiddle.h>
@@ -137,8 +138,7 @@ void SketchPlugin_Split::execute()
 
   //std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
-  getConstraints(aFeaturesToDelete, aFeaturesToUpdate, /*aTangentFeatures, */
-                 aCoincidenceToFeature);
+  getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aCoincidenceToFeature);
 
   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
   std::list<AttributePtr> aRefsToFeature;
@@ -239,18 +239,19 @@ void SketchPlugin_Split::execute()
   else if (aFeatureKind == SketchPlugin_Arc::ID())
     aNewFeature = splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
                            aCreatedFeatures, aModifiedAttributes);
+  else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
+    aNewFeature = splitEllipticArc(aSplitFeature, aBaseFeature, anAfterFeature,
+        aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
 
   restoreCurrentFeature();
 
-  if (aFeatureKind == SketchPlugin_Circle::ID()) {
-    FeaturePtr aCircleFeature = aBaseFeature;
-    aReplacingFeature = splitCircle(aSplitFeature, aBaseFeature, anAfterFeature,
+  if (aFeatureKind == SketchPlugin_Circle::ID() || aFeatureKind == SketchPlugin_Ellipse::ID()) {
+    aFeaturesToDelete.insert(aBaseFeature);
+    aReplacingFeature = splitClosed(aSplitFeature, aBaseFeature, anAfterFeature,
                                     aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
 
     updateRefFeatureConstraints(aBaseFeature->lastResult(), aRefsToFeature);
 
-    AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
-    aFeaturesToDelete.insert(aCircleFeature);
     // as circle is removed, temporary fill this attribute*/
     aBaseObjectAttr->setObject(ResultPtr());
   }
@@ -518,7 +519,8 @@ void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelet
       theFeaturesToDelete.insert(aRefFeature);
     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
       theFeaturesToUpdate.insert(aRefFeature);
-    else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
+    else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID() ||
+             aRefFeatureKind == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
       std::string anAttributeToBeModified;
       AttributePoint2DPtr aCoincidentPoint;
       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
@@ -592,7 +594,7 @@ void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
 
   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
-                                                            aCLast = theCoincidenceToFeature.end();
+                                                      aCLast = theCoincidenceToFeature.end();
 #ifdef DEBUG_SPLIT
   std::cout << std::endl;
   std::cout << "Coincidences to feature(modified):"<< std::endl;
@@ -668,10 +670,10 @@ void SketchPlugin_Split::updateRefFeatureConstraints(
 }
 
 FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
-                                             FeaturePtr& theBaseFeatureModified,
-                                             FeaturePtr& theAfterFeature,
-                                             std::set<AttributePoint2DPtr>& thePoints,
-                                             std::set<FeaturePtr>& theCreatedFeatures,
+                                         FeaturePtr& theBaseFeatureModified,
+                                         FeaturePtr& theAfterFeature,
+                                         std::set<AttributePoint2DPtr>& thePoints,
+                                         std::set<FeaturePtr>& theCreatedFeatures,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
   FeaturePtr anNewFeature;
@@ -680,16 +682,9 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                                            data()->attribute(SELECTED_OBJECT()));
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Line::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
@@ -718,8 +713,8 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
 #endif
 
   // create a split feature
-  theSplitFeature =
-    createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  theSplitFeature = SketchPlugin_SegmentationTools::createLineFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   theCreatedFeatures.insert(theSplitFeature);
 
   // before split feature
@@ -741,7 +736,8 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
       aFeature->execute(); // to update result
     }
     else {
-      aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
+      aFeature = SketchPlugin_SegmentationTools::createLineFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
       theCreatedFeatures.insert(aFeature);
       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
@@ -811,10 +807,10 @@ FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
 }
 
 FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
-                                            FeaturePtr& theBaseFeatureModified,
-                                            FeaturePtr& theAfterFeature,
-                                            std::set<AttributePoint2DPtr>& thePoints,
-                                            std::set<FeaturePtr>& theCreatedFeatures,
+                                        FeaturePtr& theBaseFeatureModified,
+                                        FeaturePtr& theAfterFeature,
+                                        std::set<AttributePoint2DPtr>& thePoints,
+                                        std::set<FeaturePtr>& theCreatedFeatures,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
   FeaturePtr anNewFeature;
@@ -823,16 +819,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                           data()->attribute(SELECTED_OBJECT()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Arc::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
@@ -859,7 +847,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
 #endif
 
   // split feature
-  theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   theCreatedFeatures.insert(theSplitFeature);
 
   // before split feature
@@ -881,7 +870,8 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
       aFeature->execute(); // to update result
     }
     else {
-      aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
+      aFeature = SketchPlugin_SegmentationTools::createArcFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
       theCreatedFeatures.insert(aFeature);
       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
@@ -960,7 +950,151 @@ FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
   return anNewFeature;
 }
 
-FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature,
+FeaturePtr SketchPlugin_Split::splitEllipticArc(FeaturePtr& theSplitFeature,
+                                                FeaturePtr& theBaseFeatureModified,
+                                                FeaturePtr& theAfterFeature,
+                                                std::set<AttributePoint2DPtr>& thePoints,
+                                                std::set<FeaturePtr>& theCreatedFeatures,
+                 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
+{
+  FeaturePtr anNewFeature;
+
+  std::set<FeaturePtr> aCreatedFeatures;
+  FeaturePtr aConstraintFeature;
+  theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
+
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
+  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
+
+  AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
+  AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
+  AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
+    setError("Error: Feature has no start and end points.");
+    return anNewFeature;
+  }
+
+  arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
+                     aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+#ifdef DEBUG_SPLIT
+  std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
+  std::cout << "Start point: " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
+  std::cout << "1st point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
+  std::cout << "2nd point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
+  std::cout << "End point:   " <<
+    ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
+#endif
+
+  // split feature
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
+  theCreatedFeatures.insert(theSplitFeature);
+
+  // before split feature
+  if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
+    theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+  }
+  else {
+    theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
+    // move end arc point to start of split
+  }
+
+  // after split feature
+  if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
+    FeaturePtr aFeature;
+    if (!theBaseFeatureModified.get()) {
+      aFeature = aBaseFeature; // use base feature to store all constraints here
+      fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
+      aFeature->execute(); // to update result
+    }
+    else {
+      aFeature = SketchPlugin_SegmentationTools::createArcFeature(
+          aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
+      theCreatedFeatures.insert(aFeature);
+      theModifiedAttributes.insert(std::make_pair(
+          anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+      anNewFeature = aFeature;
+    }
+    aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+                     SketchPlugin_ConstraintCoincidence::ID(),
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                     aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+    theCreatedFeatures.insert(aConstraintFeature);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                                (aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                                (aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+
+    if (!theBaseFeatureModified.get())
+      theBaseFeatureModified = aFeature;
+    else
+      theAfterFeature = aFeature;
+  }
+  else {
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+    theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
+        theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+  }
+  // base split, that is defined before split feature should be changed at end
+  // (after the after feature creation). Otherwise modified value will be used in after feature
+  // before split feature
+  if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
+    // move end arc point to start of split
+    fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                  aFirstPointAttrOfSplit);
+    theBaseFeatureModified->execute(); // to update result
+    aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+                     SketchPlugin_ConstraintCoincidence::ID(),
+                     theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+    theCreatedFeatures.insert(aConstraintFeature);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+  }
+  else
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                     theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+
+  // additional constraints between split and base features
+#ifdef CREATE_CONSTRAINTS
+  aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+          SketchPlugin_ConstraintEqual::ID(),
+          aBaseFeature->lastResult(),
+          theSplitFeature->lastResult());
+  theCreatedFeatures.insert(aConstraintFeature);
+  aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+          SketchPlugin_ConstraintTangent::ID(),
+          theSplitFeature->lastResult(),
+          aBaseFeature->lastResult());
+  theCreatedFeatures.insert(aConstraintFeature);
+  if (theAfterFeature.get()) {
+    aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+                SketchPlugin_ConstraintEqual::ID(),
+                aBaseFeature->lastResult(),
+                theAfterFeature->lastResult());
+    theCreatedFeatures.insert(aConstraintFeature);
+    aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
+                SketchPlugin_ConstraintTangent::ID(),
+                theSplitFeature->lastResult(),
+                theAfterFeature->lastResult());
+    theCreatedFeatures.insert(aConstraintFeature);
+  }
+#endif
+  return anNewFeature;
+}
+
+FeaturePtr SketchPlugin_Split::splitClosed(FeaturePtr& theSplitFeature,
                                                FeaturePtr& theBaseFeatureModified,
                                                FeaturePtr& theAfterFeature,
                                                std::set<AttributePoint2DPtr>& thePoints,
@@ -973,55 +1107,90 @@ FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature,
   FeaturePtr aConstraintFeature;
   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
 
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch)
-    return anNewFeature;
-
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                                           data()->attribute(SELECTED_OBJECT()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  std::string aFeatureKind = aBaseFeature->getKind();
-  if (aFeatureKind != SketchPlugin_Circle::ID())
-    return anNewFeature;
 
   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
 
   // split feature
-  theSplitFeature =
-    createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
-  bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
+  theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
+  const std::string& aReversedAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+  bool aSplitReversed = theSplitFeature->boolean(aReversedAttrName)->value();
   theCreatedFeatures.insert(theSplitFeature);
 
   // base feature is a left part of the circle
-  theBaseFeatureModified = createArcFeature(aBaseFeature,
-    aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
+  theBaseFeatureModified = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
   anNewFeature = theBaseFeatureModified;
-  std::dynamic_pointer_cast<SketchPlugin_Arc>(
-    theBaseFeatureModified)->setReversed(!aSplitReversed);
+  theBaseFeatureModified->boolean(aReversedAttrName)->setValue(!aSplitReversed);
   theBaseFeatureModified->execute();
 
-  theModifiedAttributes.insert(
-    std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
-                  theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
+  if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
+  }
+  else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
+        theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
+
+    // update the PARENT_ID reference for all the features created by the ellipse
+    const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
+    std::list<AttributePtr> aRefsToParent;
+    for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
+      if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() ||
+          (*aRef)->id() == SketchPlugin_Point::PARENT_ID())
+        aRefsToParent.push_back(*aRef);
+    }
+    for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
+         aRef != aRefsToParent.end(); ++aRef)
+      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(theSplitFeature);
+  }
 
   theCreatedFeatures.insert(theBaseFeatureModified);
 
+  const std::string& aStartAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
+  const std::string& aEndAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
+
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
+                             (theBaseFeatureModified->attribute(aStartAttrName)));
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
+                             (theBaseFeatureModified->attribute(aEndAttrName)));
 
   // additional constraints between split and base features
   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                      SketchPlugin_ConstraintCoincidence::ID(),
-                     theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
-                     theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
+                     theBaseFeatureModified->attribute(aEndAttrName),
+                     theSplitFeature->attribute(aEndAttrName));
   theCreatedFeatures.insert(aConstraintFeature);
   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                      SketchPlugin_ConstraintCoincidence::ID(),
-                     theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
-                     theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
+                     theBaseFeatureModified->attribute(aStartAttrName),
+                     theSplitFeature->attribute(aStartAttrName));
   theCreatedFeatures.insert(aConstraintFeature);
 
 #ifdef CREATE_CONSTRAINTS
@@ -1058,9 +1227,14 @@ void SketchPlugin_Split::arrangePointsOnArc(
 {
   static const double anAngleTol = 1.e-12;
 
+  const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
+  const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+
   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-  bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+      theArc->attribute(aCenterAttrName))->pnt();
+  bool isReversed = theArc->boolean(aReversedAttrName)->value();
 
   // collect directions to each point
   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
@@ -1110,71 +1284,6 @@ void SketchPlugin_Split::fillAttribute(const AttributePtr& theModifiedAttribute,
   }
 }
 
-FeaturePtr SketchPlugin_Split::createLineFeature(const FeaturePtr& theBaseFeature,
-                                                           const AttributePtr& theFirstPointAttr,
-                                                           const AttributePtr& theSecondPointAttr)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
-  fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  aFeature->execute(); // to obtain result
-
-  return aFeature;
-}
-
-FeaturePtr SketchPlugin_Split::createArcFeature(const FeaturePtr& theBaseFeature,
-                                                const AttributePtr& theFirstPointAttr,
-                                                const AttributePtr& theSecondPointAttr)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  std::string aCenterAttributeId;
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
-    aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
-  else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
-    aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
-
-  if (aCenterAttributeId.empty())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
-  // update fillet arc: make the arc correct for sure, so, it is not needed to process
-  // the "attribute updated"
-  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
-  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
-                theBaseFeature->attribute(aCenterAttributeId));
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  // fill referersed state of created arc as it is on the base arc
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-    bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
-    aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
-  }
-  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-  aFeature->execute(); // to obtain result
-
-  return aFeature;
-}
-
 #ifdef _DEBUG
 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_Split::getEdgeAttributes(
                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
index 995b5800ad2502bdc9bab40446b67ed5e4dd3b6d..1c8273b6e245cd8f5dd689777edc7eafb2348435 100644 (file)
@@ -190,6 +190,20 @@ private:
                 std::set<std::shared_ptr<ModelAPI_Feature>>& theCreatedFeatures,
                 std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
 
+  /// Make the base object is splitted by the point attributes
+  /// \param theSplitFeature a result split feature
+  /// \param theBeforeFeature a feature between start point and the 1st point of split feature
+  /// \param theAfterFeature a feature between last point of split feature and the end point
+  /// \param thePoints a list of points where coincidences will be build
+  /// \param theCreatedFeatures a container of created features
+  /// \return new elliptic arc if it was created
+  FeaturePtr splitEllipticArc(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
+                std::shared_ptr<ModelAPI_Feature>& theBeforeFeature,
+                std::shared_ptr<ModelAPI_Feature>& theAfterFeature,
+                std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+                std::set<std::shared_ptr<ModelAPI_Feature>>& theCreatedFeatures,
+                std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+
   /// Make the base object is splitted by the point attributes
   /// \param theSplitFeature a result split feature
   /// \param theBeforeFeature a feature between start point and the 1st point of split feature
@@ -197,7 +211,7 @@ private:
   /// \param thePoints a list of points where coincidences will be build
   /// \param theCreatedFeatures a container of created features
   /// \return new arc if it was created
-  FeaturePtr splitCircle(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
+  FeaturePtr splitClosed(std::shared_ptr<ModelAPI_Feature>& theSplitFeature,
                    std::shared_ptr<ModelAPI_Feature>& theBeforeFeature,
                    std::shared_ptr<ModelAPI_Feature>& theAfterFeature,
                    std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
@@ -236,22 +250,6 @@ private:
   void fillAttribute(const AttributePtr& theModifiedAttribute,
                      const AttributePtr& theSourceAttribute);
 
-  /// Creates a line feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
-                               const AttributePtr& theFirstPointAttr,
-                               const AttributePtr& theSecondPointAttr);
-
-  /// Creates an arc feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature,
-                              const AttributePtr& theFirstPointAttr,
-                              const AttributePtr& theSecondPointAttr);
-
   /// Returns attributes of the feature, used in edge build, for arc it is end and start points
   /// \param theFeature a feature
   /// \return container of attributes
index 5aa9c1bf1bfc857930128711ab7fccda794d20f6..a285ea2431c1e7b8a2364b91047292a88f43e56e 100644 (file)
@@ -20,6 +20,7 @@
 #include "SketchPlugin_Tools.h"
 
 #include "SketchPlugin_Arc.h"
+#include "SketchPlugin_Circle.h"
 #include "SketchPlugin_ConstraintCoincidence.h"
 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
 #include "SketchPlugin_ConstraintLength.h"
@@ -845,3 +846,118 @@ AISObjectPtr SketchPlugin_SegmentationTools::getAISObject(
     anAIS = AISObjectPtr();
   return anAIS;
 }
+
+#define GEOM_DATA_POINT2D(f, a) std::dynamic_pointer_cast<GeomDataAPI_Point2D>((f)->attribute(a))
+
+FeaturePtr SketchPlugin_SegmentationTools::createLineFeature(
+    const FeaturePtr& theBaseFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
+{
+  FeaturePtr aFeature;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
+  SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
+  if (!aSketch || !theBaseFeature.get())
+    return aFeature;
+
+  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+
+  GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::START_ID())->setValue(theFirstPoint);
+  GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::END_ID())->setValue(theSecondPoint);
+
+  aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+      theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+  aFeature->execute(); // to obtain result
+
+  return aFeature;
+}
+
+struct ArcAttributes
+{
+  std::string myKind;
+  std::string myCenter;
+  std::string myFocus;
+  std::string myStart;
+  std::string myEnd;
+  std::string myReversed;
+
+  ArcAttributes() {}
+
+  ArcAttributes(const std::string& theKind) : myKind(theKind)
+  {
+    if (myKind == SketchPlugin_Arc::ID()) {
+      myCenter = SketchPlugin_Arc::CENTER_ID();
+      myStart = SketchPlugin_Arc::START_ID();
+      myEnd = SketchPlugin_Arc::END_ID();
+      myReversed = SketchPlugin_Arc::REVERSED_ID();
+    }
+    else if (myKind == SketchPlugin_Circle::ID()) {
+      myCenter = SketchPlugin_Circle::CENTER_ID();
+    }
+    else if (myKind == SketchPlugin_Ellipse::ID()) {
+      myCenter = SketchPlugin_Ellipse::CENTER_ID();
+      myFocus = SketchPlugin_Ellipse::FIRST_FOCUS_ID();
+    }
+    else if (myKind == SketchPlugin_EllipticArc::ID()) {
+      myCenter = SketchPlugin_EllipticArc::CENTER_ID();
+      myFocus = SketchPlugin_EllipticArc::FIRST_FOCUS_ID();
+      myStart = SketchPlugin_EllipticArc::START_POINT_ID();
+      myEnd = SketchPlugin_EllipticArc::END_POINT_ID();
+      myReversed = SketchPlugin_EllipticArc::REVERSED_ID();
+    }
+  }
+};
+
+FeaturePtr SketchPlugin_SegmentationTools::createArcFeature(
+    const FeaturePtr& theBaseFeature,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+    const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
+{
+  FeaturePtr aFeature;
+  std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
+  SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
+  if (!aSketch || !theBaseFeature.get())
+    return aFeature;
+
+  ArcAttributes aBaseAttrs(theBaseFeature->getKind());
+  ArcAttributes aTargetAttrs;
+  if (aBaseAttrs.myKind == SketchPlugin_Arc::ID() ||
+      aBaseAttrs.myKind == SketchPlugin_Circle::ID())
+    aTargetAttrs = ArcAttributes(SketchPlugin_Arc::ID());
+  else if (aBaseAttrs.myKind == SketchPlugin_Ellipse::ID() ||
+           aBaseAttrs.myKind == SketchPlugin_EllipticArc::ID())
+    aTargetAttrs = ArcAttributes(SketchPlugin_EllipticArc::ID());
+
+  if (aTargetAttrs.myKind.empty())
+    return aFeature;
+
+  aFeature = aSketch->addFeature(aTargetAttrs.myKind);
+  // update fillet arc: make the arc correct for sure, so, it is not needed to process
+  // the "attribute updated"
+  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
+  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
+
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myCenter)->setValue(
+      GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myCenter)->pnt());
+  if (!aTargetAttrs.myFocus.empty()) {
+    GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myFocus)->setValue(
+        GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myFocus)->pnt());
+  }
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myStart)->setValue(theFirstPoint);
+  GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myEnd)->setValue(theSecondPoint);
+
+  aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+      theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
+
+  /// fill referersed state of created arc as it is on the base arc
+  bool aReversed = aBaseAttrs.myReversed.empty() ? false :
+                   theBaseFeature->boolean(aBaseAttrs.myReversed)->value();
+  aFeature->boolean(aTargetAttrs.myReversed)->setValue(aReversed);
+
+  aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
+  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
+
+  return aFeature;
+}
index 74193772e09097fa388e8289ff3f2fb841ac25e6..f29e192dffa83622bd7b849635dd80738fe1c194 100644 (file)
@@ -206,6 +206,25 @@ namespace SketchPlugin_SegmentationTools
   /// \param theFeaturesToUpdate a constraint index
   void updateFeaturesAfterOperation(const std::set<FeaturePtr>& theFeaturesToUpdate);
 
+
+  /// Creates a line feature filled by center of base feature and given points
+  /// \param theBaseFeature another arc feature
+  /// \param theFirstAttribute an attribute with coordinates for the start point
+  /// \param theSecondAttribute an attribute with coordinates for the end point
+  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
+                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
+
+  /// Creates a circular/elliptic arc feature filled by center
+  /// (or by center and focus for elliptic arc) of base feature and given points
+  /// \param theBaseFeature     another circle or ellipse or circular/elliptic arc
+  /// \param theFirstAttribute  an attribute with coordinates for the start point
+  /// \param theSecondAttribute an attribute with coordinates for the end point
+  FeaturePtr createArcFeature(
+      const FeaturePtr& theBaseFeature,
+      const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+      const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
+
 }; // namespace SketchPlugin_SegmentationTools
 
 #endif // SKETCHPLUGIN_TOOLS_H_
\ No newline at end of file
index 0be8a5a5f9ec4d8c5daee97621ca8508c32d86c1..b5c215c629a7a03a734749a660293e142ffda615 100644 (file)
@@ -47,6 +47,8 @@
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintCollinear.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
@@ -64,6 +66,7 @@
 
 #include <cmath>
 
+#define DEBUG_TRIM
 #ifdef DEBUG_TRIM
 #include <iostream>
 #endif
@@ -304,8 +307,9 @@ void SketchPlugin_Trim::execute()
   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
   const std::string& aKind = aBaseFeature->getKind();
   FeaturePtr aReplacingFeature, aNewFeature;
-  if (aKind == SketchPlugin_Circle::ID()) {
-    aReplacingFeature = trimCircle(aStartShapePoint2d, aLastShapePoint2d,
+  if (aKind == SketchPlugin_Circle::ID() ||
+      aKind == SketchPlugin_Ellipse::ID()) {
+    aReplacingFeature = trimClosed(aStartShapePoint2d, aLastShapePoint2d,
                aFurtherCoincidences, aModifiedAttributes);
 
     aFeaturesToDelete.insert(aBaseFeature);
@@ -322,6 +326,10 @@ void SketchPlugin_Trim::execute()
     aNewFeature = trimArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
                           aFurtherCoincidences, aModifiedAttributes);
   }
+  else if (aKind == SketchPlugin_EllipticArc::ID()) {
+    aNewFeature = trimEllipticArc(aStartShapePoint2d, aLastShapePoint2d, aBaseRefAttributes,
+                          aFurtherCoincidences, aModifiedAttributes);
+  }
 
   restoreCurrentFeature();
 
@@ -382,7 +390,7 @@ void SketchPlugin_Trim::execute()
   ResultPtr aReplacingResult;
   if (aReplacingFeature.get()) {
     aReplacingFeature->execute(); // need it to obtain result
-    aReplacingResult = getFeatureResult(aReplacingFeature);
+    aReplacingResult = aReplacingFeature->lastResult();
   }
   for(std::list<AttributePtr>::const_iterator anIt = aRefsToFeature.begin(),
                                           aLast = aRefsToFeature.end();
@@ -457,7 +465,7 @@ void SketchPlugin_Trim::execute()
       aPreviewObject = ObjectPtr();
 
       aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
-      aBaseObject = getFeatureResult(aBaseFeature);
+      aBaseObject = aBaseFeature->lastResult();
       std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
                                                                 aPreviewPnt2d->y());
       ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
@@ -468,7 +476,7 @@ void SketchPlugin_Trim::execute()
           aPreviewObject = aBaseResult;
       }
       if (!aPreviewObject.get() && aNewFeature.get()) {
-        ResultPtr aNewFeatureResult = getFeatureResult(aNewFeature);
+        ResultPtr aNewFeatureResult = aNewFeature->lastResult();
         if (aNewFeatureResult.get()) {
           GeomShapePtr aShape = aNewFeatureResult->shape();
           std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
@@ -643,7 +651,7 @@ void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete
   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
                                          aData->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
-  ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
+  ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
 
   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
@@ -771,7 +779,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& the
     // result is two lines: start line point - start shape point,
     // last shape point - last line point
     // create second line
-    anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint);
+    anNewFeature = SketchPlugin_SegmentationTools::createLineFeature(
+        aBaseFeature, aLastShapePoint, aLastFeaturePoint);
     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
                                (anNewFeature->attribute(SketchPlugin_Line::START_ID())));
 
@@ -789,8 +798,8 @@ FeaturePtr SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& the
     // Collinear constraint for lines
     SketchPlugin_Tools::createConstraintObjectObject(sketch(),
                                          SketchPlugin_ConstraintCollinear::ID(),
-                                         getFeatureResult(aBaseFeature),
-                                         getFeatureResult(anNewFeature));
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
   }
   return anNewFeature;
 }
@@ -857,7 +866,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
   else {
     // result is two arcs: start arc point - start shape point, last shape point - last arc point
     // create second arc
-    anNewFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint);
+    anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+        aBaseFeature, aLastShapePoint, aLastArcPoint);
     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
                                (anNewFeature->attribute(SketchPlugin_Arc::START_ID())));
 
@@ -875,8 +885,8 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
     // equal Radius constraint for arcs
     SketchPlugin_Tools::createConstraintObjectObject(sketch(),
                                          SketchPlugin_ConstraintEqual::ID(),
-                                         getFeatureResult(aBaseFeature),
-                                         getFeatureResult(anNewFeature));
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
     // coincident centers constraint
     SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
                                          SketchPlugin_ConstraintCoincidence::ID(),
@@ -892,34 +902,172 @@ FeaturePtr SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theS
   return anNewFeature;
 }
 
-FeaturePtr SketchPlugin_Trim::trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
-                                   const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
-                                   std::set<AttributePoint2DPtr>& thePoints,
+FeaturePtr SketchPlugin_Trim::trimEllipticArc(
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                 std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+                 std::set<AttributePoint2DPtr>& thePoints,
                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
 {
+  FeaturePtr anNewFeature;
   // Check the base objects are initialized.
-  AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
-                                        data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
   ObjectPtr aBaseObject = aBaseObjectAttr->value();
   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
 
-  /// points of trim
-  //AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
-  //getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+  // points of trim
+  AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
+  SketchPlugin_SegmentationTools::getFeaturePoints(
+      aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
+
+  std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
+  std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
+  arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
+                     aStartShapePoint, aLastShapePoint);
+#ifdef DEBUG_TRIM
+  std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
+  if (aStartShapePoint.get())
+    std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
+                                       aStartShapePoint->y() << "]" << std::endl;
+  std::cout << "Start arc attribute point:   [" << aStartArcPoint->x() << ", " <<
+                                   aStartArcPoint->y() << "]" << std::endl;
+  if (aLastShapePoint.get())
+    std::cout << "Last shape point:   [" << aLastShapePoint->x() << ", " <<
+                                     aLastShapePoint->y() << "]" << std::endl;
+  std::cout << "Last arc attribute point:   [" << aLastArcPoint->x() << ", " <<
+                                   aLastArcPoint->y() << "]" << std::endl;
+#endif
+
+  bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
+  bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
+  if (isStartPoint || isLastPoint) {
+    // result is one arc: changed existing arc
+    std::string aModifiedAttribute = isStartPoint ? SketchPlugin_EllipticArc::START_POINT_ID()
+                                                  : SketchPlugin_EllipticArc::END_POINT_ID();
+    std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+    if (aStartShapePoint.get() && aLastShapePoint.get())
+      aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
+    else
+      aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
+
+    removeReferencesToAttribute(aBaseFeature->attribute(aModifiedAttribute),
+                                theBaseRefAttributes);
+
+    fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                               (aBaseFeature->attribute(aModifiedAttribute)));
+  }
+  else {
+    // result is two arcs: start arc point - start shape point, last shape point - last arc point
+    // create second arc
+    anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+        aBaseFeature, aLastShapePoint, aLastArcPoint);
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                     anNewFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
+
+    std::string aModifiedAttribute = SketchPlugin_EllipticArc::END_POINT_ID();
+    theModifiedAttributes.insert(
+      std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
+                     anNewFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
+
+    // modify base arc
+    fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
+
+    thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
+                               (aBaseFeature->attribute(aModifiedAttribute)));
 
-  /// trim feature
-  FeaturePtr anNewFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint);
+    // make elliptic arcs equal
+    SketchPlugin_Tools::createConstraintObjectObject(sketch(),
+                                         SketchPlugin_ConstraintEqual::ID(),
+                                         aBaseFeature->lastResult(),
+                                         anNewFeature->lastResult());
+    // coincident centers constraint
+    SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
+        SketchPlugin_ConstraintCoincidence::ID(),
+        aBaseFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+
+#ifdef DEBUG_TRIM
+    std::cout << "Created arc on points:" << std::endl;
+    std::cout << "Start shape point: [" << aStartShapePoint->x() << ", " <<
+                                           aStartShapePoint->y() << "]" << std::endl;
+#endif
+  }
+  return anNewFeature;
+}
+
+FeaturePtr SketchPlugin_Trim::trimClosed(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                                         const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                                         std::set<AttributePoint2DPtr>& thePoints,
+                           std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
+{
+  // Check the base objects are initialized.
+  AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
+  ObjectPtr aBaseObject = aBaseObjectAttr->value();
+  FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
+
+  // trim feature
+  FeaturePtr anNewFeature = SketchPlugin_SegmentationTools::createArcFeature(
+      aBaseFeature, theStartShapePoint, theLastShapePoint);
   // arc created by trim of circle is always correct, that means that it is not inversed
-  anNewFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(false);
+  const std::string& aReversedAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+  anNewFeature->boolean(aReversedAttrName)->setValue(false);
+
+  if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+    theModifiedAttributes.insert(
+      std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
+                     anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
+  }
+  else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
+    theModifiedAttributes.insert(std::make_pair(
+        aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
+        anNewFeature->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
+
+    // update the PARENT_ID reference for all the features created by the ellipse
+    const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
+    std::list<AttributePtr> aRefsToParent;
+    for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
+      if ((*aRef)->id() == SketchPlugin_Line::PARENT_ID() ||
+          (*aRef)->id() == SketchPlugin_Point::PARENT_ID())
+        aRefsToParent.push_back(*aRef);
+    }
+    for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
+         aRef != aRefsToParent.end(); ++aRef)
+      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(anNewFeature);
+  }
 
-  theModifiedAttributes.insert(
-    std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
-                   anNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
+  const std::string& aStartAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
+  const std::string& aEndAttrName = anNewFeature->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
 
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (anNewFeature->attribute(SketchPlugin_Arc::START_ID())));
+                             (anNewFeature->attribute(aStartAttrName)));
   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
-                             (anNewFeature->attribute(SketchPlugin_Arc::END_ID())));
+                             (anNewFeature->attribute(aEndAttrName)));
 
   return anNewFeature;
 }
@@ -952,9 +1100,14 @@ void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc,
 
   static const double anAngleTol = 1.e-12;
 
+  const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
+  const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
+      SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
+
   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-  bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
+      theArc->attribute(aCenterAttrName))->pnt();
+  bool isReversed = theArc->boolean(aReversedAttrName)->value();
 
   // collect directions to each point
   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
@@ -998,7 +1151,6 @@ void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttrib
   }
 }
 
-
 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
                                       const AttributePtr& theSourceAttribute)
 {
@@ -1022,100 +1174,3 @@ void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
       aModifiedAttribute->setValue(aSourceAttribute->value());
   }
 }
-
-FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature,
-                                        const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                                        const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
-{
-#ifdef DEBUG_TRIM
-  std::cout << "---- createLineFeature ---" << std::endl;
-#endif
-
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
-
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint);
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  aFeature->execute(); // to obtain result
-
-#ifdef DEBUG_TRIM
-  std::cout << "---- createLineFeature:end ---" << std::endl;
-#endif
-
-  return aFeature;
-}
-
-FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature,
-                                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
-{
-  FeaturePtr aFeature;
-  SketchPlugin_Sketch* aSketch = sketch();
-  if (!aSketch || !theBaseFeature.get())
-    return aFeature;
-
-  std::string aCenterAttributeId;
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
-    aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
-  else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
-    aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
-
-  if (aCenterAttributeId.empty())
-    return aFeature;
-
-#ifdef DEBUG_TRIM
-  std::cout << "---- createArcFeature ---" << std::endl;
-#endif
-
-  aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
-  // update fillet arc: make the arc correct for sure, so, it is not needed to process
-  // the "attribute updated"
-  // by arc; moreover, it may cause cyclicity in hte mechanism of updater
-  bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
-                theBaseFeature->attribute(aCenterAttributeId));
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint);
-  fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint);
-
-  fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
-                theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
-
-  /// fill referersed state of created arc as it is on the base arc
-  if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-    bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
-    aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
-  }
-  aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
-  aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
-
-  #ifdef DEBUG_TRIM
-  std::cout << "---- createArcFeature:end ---" << std::endl;
-  #endif
-
-  return aFeature;
-}
-
-std::shared_ptr<ModelAPI_Result> SketchPlugin_Trim::getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature)
-{
-  std::shared_ptr<ModelAPI_Result> aResult;
-
-  std::string aFeatureKind = theFeature->getKind();
-  if (aFeatureKind == SketchPlugin_Line::ID())
-    aResult = theFeature->firstResult();
-  else if (aFeatureKind == SketchPlugin_Arc::ID())
-    aResult = theFeature->lastResult();
-  else if (aFeatureKind == SketchPlugin_Circle::ID())
-    aResult = theFeature->lastResult();
-
-  return aResult;
-}
index 91b9405d81f1ad146f9ea8dd12722460999f2dae..365cda33cec49e576cd12bce33e628361c374b8d 100644 (file)
@@ -151,10 +151,19 @@ private:
 
   /// Make the base object is splitted by the point attributes
   /// \param thePoints a list of points where coincidences will be build
-  FeaturePtr trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
-                  const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
-                  std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
-                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+  /// \return new elliptic arc if it was created
+  FeaturePtr trimEllipticArc(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+               const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+               std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
+               std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+               std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
+
+  /// Make the base object is splitted by the point attributes
+  /// \param thePoints a list of points where coincidences will be build
+  FeaturePtr trimClosed(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
+                        const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
+                        std::set<std::shared_ptr<GeomDataAPI_Point2D> >& thePoints,
+                        std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes);
 
   /// Correct the first and the second point to provide condition that the first is closer to
   /// the start point and the second point - to the last end of current segment. To rearrange
@@ -194,28 +203,6 @@ private:
   void fillPointAttribute(const AttributePtr& theModifiedAttribute,
                           const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
 
-  /// Creates a line feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                               const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
-
-  /// Creates an arc feature filled by center of base feature and given points
-  /// \param theBaseFeature another arc feature
-  /// \param theFirstAttribute an attribute with coordinates for the start point
-  /// \param theSecondAttribute an attribute with coordinates for the end point
-  FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature,
-                              const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
-                              const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint);
-
-  /// Result result of the feature to build constraint with. For arc, circle it is an edge result.
-  /// \param theFeature a feature
-  /// \return result object
-  std::shared_ptr<ModelAPI_Result> getFeatureResult(
-                                    const std::shared_ptr<ModelAPI_Feature>& theFeature);
-
 private:
   void findShapePoints(const std::string& theObjectAttributeId,
                        const std::string& thePointAttributeId,
index 0ee6f65f3aa4a5b76ab718740ec7b342d18f2bb0..1d5cc9c739734ddb6f4e82ba607b9707b3bc5880 100644 (file)
@@ -965,6 +965,8 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
   GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
   std::shared_ptr<SketchPlugin_Feature> aSFeature =
                                 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
+  if (!aSFeature)
+    return false;
   SketchPlugin_Sketch* aSketch = aSFeature->sketch();
 
   std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
index 35cbb4d722daca0db3431ee468d7bd03919e922f..7f416c66b289c62c89b881cac373959e52f111a3 100644 (file)
@@ -76,6 +76,10 @@ static ConstraintWrapperPtr
   createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType,
                                 std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
                                 std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+static ConstraintWrapperPtr
+  createConstraintPointsCollinear(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+                                  std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
+                                  std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint3);
 static ConstraintWrapperPtr
   createConstraintDistancePointPoint(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
                                      std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
@@ -194,13 +198,15 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
 
   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint1 = GCS_POINT_WRAPPER(thePoint1);
   std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint2 = GCS_POINT_WRAPPER(thePoint2);
+  std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity1 = GCS_EDGE_WRAPPER(theEntity1);
 
   switch (theType) {
   case CONSTRAINT_PT_PT_COINCIDENT:
     aResult = createConstraintCoincidence(aPoint1, aPoint2);
     break;
   case CONSTRAINT_PT_ON_CURVE:
-    aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_EDGE_WRAPPER(theEntity1));
+    aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1):
+              createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
     break;
   case CONSTRAINT_MIDDLE_POINT:
     aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2);
@@ -211,34 +217,31 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
   case CONSTRAINT_PT_LINE_DISTANCE:
     aResult = createConstraintDistancePointLine(GCS_SCALAR_WRAPPER(theValue),
                                                 aPoint1,
-                                                GCS_EDGE_WRAPPER(theEntity1));
+                                                anEntity1);
     break;
   case CONSTRAINT_HORIZONTAL_DISTANCE:
   case CONSTRAINT_VERTICAL_DISTANCE:
     aResult = createConstraintHVDistance(theType, GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2);
     break;
   case CONSTRAINT_RADIUS:
-    aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue),
-                                     GCS_EDGE_WRAPPER(theEntity1));
+    aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue), anEntity1);
     break;
   case CONSTRAINT_ANGLE:
     aResult = createConstraintAngle(theConstraint,
                   GCS_SCALAR_WRAPPER(theValue),
-                  GCS_EDGE_WRAPPER(theEntity1), GCS_EDGE_WRAPPER(theEntity2));
+                  anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_FIXED:
     break;
   case CONSTRAINT_HORIZONTAL:
   case CONSTRAINT_VERTICAL:
-    aResult = createConstraintHorizVert(theType, GCS_EDGE_WRAPPER(theEntity1));
+    aResult = createConstraintHorizVert(theType, anEntity1);
     break;
   case CONSTRAINT_PARALLEL:
-    aResult = createConstraintParallel(GCS_EDGE_WRAPPER(theEntity1),
-                                       GCS_EDGE_WRAPPER(theEntity2));
+    aResult = createConstraintParallel(anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_PERPENDICULAR:
-    aResult = createConstraintPerpendicular(GCS_EDGE_WRAPPER(theEntity1),
-                                            GCS_EDGE_WRAPPER(theEntity2));
+    aResult = createConstraintPerpendicular(anEntity1, GCS_EDGE_WRAPPER(theEntity2));
     break;
   case CONSTRAINT_EQUAL_LINES:
   case CONSTRAINT_EQUAL_ELLIPSES:
@@ -246,7 +249,7 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
   case CONSTRAINT_EQUAL_LINE_ARC:
   case CONSTRAINT_EQUAL_RADIUS:
     aResult = createConstraintEqual(theType,
-                                    GCS_EDGE_WRAPPER(theEntity1),
+                                    anEntity1,
                                     GCS_EDGE_WRAPPER(theEntity2),
                                     anIntermediate);
     break;
@@ -450,6 +453,17 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
   return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType));
 }
 
+ConstraintWrapperPtr createConstraintPointsCollinear(
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
+    std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint3)
+{
+  GCSConstraintPtr aNewConstr(new GCS::ConstraintPointOnLine(
+      *(thePoint1->point()), *(thePoint2->point()), *(thePoint3->point())));
+  return ConstraintWrapperPtr(
+      new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PT_ON_CURVE));
+}
+
 ConstraintWrapperPtr createConstraintMiddlePoint(
     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
     std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
index b0520c45a0bb713705f89d5e8b905b02b3865ebd..2c4d8eed34c4ba26b201246f51442f8a96a4b7ce 100644 (file)
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
+#include <GeomDataAPI_Point2D.h>
+
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
 
 static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint,
                                             const StoragePtr& theStorage,
@@ -44,8 +50,146 @@ static void getCoincidentFeatureExtremities(const ConstraintPtr& theConstraint,
     } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
       theExtremities[0] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::START_ID()));
       theExtremities[1] = theStorage->entity(aFeature->attribute(SketchPlugin_Arc::END_ID()));
+    } else if (aFeature->getKind() == SketchPlugin_EllipticArc::ID()) {
+      theExtremities[0] = theStorage->entity(
+          aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+      theExtremities[1] = theStorage->entity(
+          aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
+    }
+  }
+}
+
+static void getPointOwnerAndParent(const AttributeRefAttrPtr theRefAttr,
+                                   AttributePoint2DPtr& thePoint,
+                                   FeaturePtr& theOwner,
+                                   FeaturePtr& theParent)
+{
+  AttributePtr anAttr = theRefAttr->attr();
+  if (theRefAttr->isObject()) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature(theRefAttr->object());
+    if (anOwner && anOwner->getKind() == SketchPlugin_Point::ID())
+      anAttr = anOwner->attribute(SketchPlugin_Point::COORD_ID());
+    else
+      return;
+  }
+  thePoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+  if (thePoint) {
+    theOwner = ModelAPI_Feature::feature(thePoint->owner());
+    if (theOwner) {
+      std::string aParentRefID;
+      if (theOwner->getKind() == SketchPlugin_Line::ID())
+        aParentRefID = SketchPlugin_Line::PARENT_ID();
+      else if (theOwner->getKind() == SketchPlugin_Point::ID())
+        aParentRefID = SketchPlugin_Point::PARENT_ID();
+      if (!aParentRefID.empty()) {
+        AttributeReferencePtr aParentRef = theOwner->reference(aParentRefID);
+        theParent = aParentRef ? ModelAPI_Feature::feature(aParentRef->value()) : FeaturePtr();
+      }
+    }
+  }
+}
+
+static void ellipseDiameters(FeaturePtr theEllipse,
+                             std::pair<std::string, std::string>& theMajorAxis,
+                             std::pair<std::string, std::string>& theMinorAxis)
+{
+  if (theEllipse->getKind() == SketchPlugin_Ellipse::ID()) {
+    theMajorAxis.first = SketchPlugin_Ellipse::MAJOR_AXIS_START_ID();
+    theMajorAxis.second = SketchPlugin_Ellipse::MAJOR_AXIS_END_ID();
+    theMinorAxis.first = SketchPlugin_Ellipse::MINOR_AXIS_START_ID();
+    theMinorAxis.second = SketchPlugin_Ellipse::MINOR_AXIS_END_ID();
+  } else if (theEllipse->getKind() == SketchPlugin_EllipticArc::ID()) {
+    theMajorAxis.first = SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID();
+    theMajorAxis.second = SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID();
+    theMinorAxis.first = SketchPlugin_EllipticArc::MINOR_AXIS_START_ID();
+    theMinorAxis.second = SketchPlugin_EllipticArc::MINOR_AXIS_END_ID();
+  }
+}
+
+static void findDiameterOnEllipse(FeaturePtr theConstruction,
+                                  FeaturePtr theEllipse,
+                                  AttributePtr& theStart,
+                                  AttributePtr& theEnd)
+{
+  AttributePtr anEllipseAttr;
+  const std::set<AttributePtr>& aRefs = theConstruction->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+    if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+      AttributeRefAttrPtr aRefAttr;
+      if ((*aRefIt)->id() == SketchPlugin_Constraint::ENTITY_A())
+        aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B());
+      else
+        aRefAttr = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A());
+      anEllipseAttr = aRefAttr->attr();
+      break;
     }
   }
+  if (!anEllipseAttr)
+    return;
+
+  std::pair<std::string, std::string> aMajorAxis, aMinorAxis;
+  ellipseDiameters(theEllipse, aMajorAxis, aMinorAxis);
+  if (anEllipseAttr->id() == aMajorAxis.first) {
+    theStart = anEllipseAttr;
+    theEnd = theEllipse->attribute(aMajorAxis.second);
+  }
+  else if (anEllipseAttr->id() == aMajorAxis.second) {
+    theStart = theEllipse->attribute(aMajorAxis.first);
+    theEnd = anEllipseAttr;
+  }
+  else if (anEllipseAttr->id() == aMinorAxis.first) {
+    theStart = anEllipseAttr;
+    theEnd = theEllipse->attribute(aMinorAxis.second);
+  }
+  else if (anEllipseAttr->id() == aMinorAxis.second) {
+    theStart = theEllipse->attribute(aMinorAxis.first);
+    theEnd = anEllipseAttr;
+  }
+}
+
+static void processEllipticArcExtremities(SketchSolver_ConstraintType& theType,
+                                          const ConstraintPtr& theConstraint,
+                                          const StoragePtr& theStorage,
+                                          std::vector<EntityWrapperPtr>& theAttributes,
+                                          EntityWrapperPtr theExtremities[2])
+{
+  AttributePoint2DPtr aPointA, aPointB;
+  FeaturePtr anOwnerA, anOwnerB;
+  FeaturePtr aParentA, aParentB;
+  getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()),
+                         aPointA, anOwnerA, aParentA);
+  getPointOwnerAndParent(theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()),
+                         aPointB, anOwnerB, aParentB);
+
+  AttributePtr anAxisStart, anAxisEnd, aPoint;
+  FeaturePtr aConstruction, anEllipticArc;
+  if (aParentA && aParentA == anOwnerB) {
+    aPoint = aPointB;
+    aConstruction = anOwnerA;
+    anEllipticArc = anOwnerB;
+  }
+  else if (aParentB && aParentB == anOwnerA) {
+    aPoint = aPointA;
+    aConstruction = anOwnerB;
+    anEllipticArc = anOwnerA;
+  }
+
+  if (!anEllipticArc || anEllipticArc->getKind() != SketchPlugin_EllipticArc::ID() ||
+      (aPoint->id() != SketchPlugin_EllipticArc::START_POINT_ID() &&
+       aPoint->id() != SketchPlugin_EllipticArc::END_POINT_ID()))
+    return;
+
+  findDiameterOnEllipse(aConstruction, anEllipticArc, anAxisStart, anAxisEnd);
+
+  if (anAxisStart && anAxisEnd) {
+    theAttributes[0] = theStorage->entity(aPoint);
+    theAttributes[1] = theStorage->entity(anAxisStart);
+    theAttributes[2] = theStorage->entity(anAxisEnd);
+    theType = CONSTRAINT_PT_ON_CURVE;
+    getCoincidentFeatureExtremities(theConstraint, theStorage, theExtremities);
+  }
 }
 
 
@@ -93,9 +237,14 @@ void SketchSolver_ConstraintCoincidence::getAttributes(
     return;
   }
 
-  if (theAttributes[1])
+  if (theAttributes[1]) {
     myType = CONSTRAINT_PT_PT_COINCIDENT;
-  else if (theAttributes[2]) {
+    // if elliptic arc boundary point is connected with one of ellipse characteristics,
+    // it should be changed from point-point coincidence to coincidence between point
+    // and axis of the ellipse to decrease only 1 DoF instead of 2 DoF and avoid overconstraint.
+    processEllipticArcExtremities(myType, myBaseConstraint, myStorage,
+                                  theAttributes, myFeatureExtremities);
+  } else if (theAttributes[2]) {
     myType = CONSTRAINT_PT_ON_CURVE;
     // obtain extremity points of the coincident feature for further checking of multi-coincidence
     getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
@@ -109,6 +258,32 @@ void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr&      theFeatur
   PlaneGCSSolver_UpdateCoincidence* anUpdater =
       static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
   bool isAccepted = anUpdater->addCoincidence(myAttributes.front(), myAttributes.back());
+  // additionally process internal coincidence, set point coincident with ellipse/elliptic arc
+  // for correct processing further coincidences set by the user
+  if (isAccepted &&
+      myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+    AttributeRefAttrPtr aRefAttrA = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+    AttributeRefAttrPtr aRefAttrB = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+    if (aRefAttrA && aRefAttrB) {
+      AttributePoint2DPtr anAttrA, anAttrB;
+      FeaturePtr anOwnerA, anOwnerB;
+      FeaturePtr aParentA, aParentB;
+      getPointOwnerAndParent(aRefAttrA, anAttrA, anOwnerA, aParentA);
+      getPointOwnerAndParent(aRefAttrB, anAttrB, anOwnerB, aParentB);
+
+      EntityWrapperPtr aPoint, anEntity;
+      if (aParentA == anOwnerB) {
+        aPoint = myStorage->entity(anAttrA);
+        anEntity = myStorage->entity(anOwnerB);
+      }
+      else if (aParentB == anOwnerA) {
+        aPoint = myStorage->entity(anAttrB);
+        anEntity = myStorage->entity(anOwnerA);
+      }
+      if (aPoint && anEntity)
+        anUpdater->addCoincidence(aPoint, anEntity);
+    }
+  }
 
   // additionally check the point is coincident to extremity of coincident feature
   if (myFeatureExtremities[0] && myFeatureExtremities[1]) {