]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #2026: Removal of construction lines automatically created by Fillet
authordbv <dbv@opencascade.com>
Fri, 10 Mar 2017 08:55:38 +0000 (11:55 +0300)
committerdbv <dbv@opencascade.com>
Fri, 10 Mar 2017 08:55:38 +0000 (11:55 +0300)
Creation fillet by one point.

src/PartSet/PartSet_SketcherMgr.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp [deleted file]
src/SketchPlugin/SketchPlugin_ConstraintFillet.h [deleted file]
src/SketchPlugin/SketchPlugin_Fillet.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Fillet.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_msg_en.ts
src/SketchPlugin/plugin-Sketch.xml

index ccd18aed06d71d54fbe0cc7bfe22897e8b049710..5497da37a30250a710f08e7ef658a7a6965d37ff 100755 (executable)
@@ -60,7 +60,7 @@
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
 #include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCollinear.h>
index fdc8a71fb49940ddb1e28619e24b4558ffeed278..e9953784c604f6c6b0cbb0cad5fd0555e90fb9c5 100644 (file)
@@ -14,7 +14,7 @@
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintMiddle.h>
@@ -607,7 +607,7 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setFillet(
     const ModelHighAPI_Double & theRadius)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
-      compositeFeature()->addFeature(SketchPlugin_ConstraintFillet::ID());
+      compositeFeature()->addFeature(SketchPlugin_Fillet::ID());
   fillAttribute(thePoints, aFeature->data()->refattrlist(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(theRadius, aFeature->real(SketchPlugin_Constraint::VALUE()));
   aFeature->execute();
index a6c654e09ec59117dbfb1a6ef991c4a9613a4c1d..46448c8a4500937853998f277ef50af98bc84a18 100644 (file)
@@ -14,7 +14,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintCollinear.h
     SketchPlugin_ConstraintDistance.h
     SketchPlugin_ConstraintEqual.h
-    SketchPlugin_ConstraintFillet.h
+    SketchPlugin_Fillet.h
     SketchPlugin_ConstraintHorizontal.h
     SketchPlugin_ConstraintLength.h
     SketchPlugin_ConstraintMiddle.h
@@ -52,7 +52,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintCollinear.cpp
     SketchPlugin_ConstraintDistance.cpp
     SketchPlugin_ConstraintEqual.cpp
-    SketchPlugin_ConstraintFillet.cpp
+    SketchPlugin_Fillet.cpp
     SketchPlugin_ConstraintHorizontal.cpp
     SketchPlugin_ConstraintLength.cpp
     SketchPlugin_ConstraintMiddle.cpp
@@ -139,7 +139,6 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintMiddlePoint.py
                TestMultiRotation.py
                TestMultiTranslation.py
-               TestFillet.py
                TestRectangle.py
                TestProjection.py
                TestSplit.py
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp b/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp
deleted file mode 100644 (file)
index 83fde70..0000000
+++ /dev/null
@@ -1,1119 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
-
-// File:    SketchPlugin_ConstraintFillet.cpp
-// Created: 19 Mar 2015
-// Author:  Artem ZHIDKOV
-
-#include "SketchPlugin_ConstraintFillet.h"
-
-#include <GeomAPI_Circ2d.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Lin2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttrList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_Session.h>
-#include <ModelAPI_Validator.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_Tools.h>
-
-#include <Events_Loop.h>
-
-#include <math.h>
-
-const double tolerance = 1.e-7;
-const double paramTolerance = 1.e-4;
-
-/// \brief Attract specified point on theNewArc to the attribute of theFeature
-static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
-  FeaturePtr theFeature, const std::string& theFeatureAttribute);
-
-/// \brief Calculates center of fillet arc and coordinates of tangency points
-static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
-                                  double theRadius, bool theNotInversed[2],
-                                  std::shared_ptr<GeomAPI_XY>& theCenter,
-                                  std::shared_ptr<GeomAPI_XY>& theTangentA,
-                                  std::shared_ptr<GeomAPI_XY>& theTangentB);
-
-/// Get point on 1/3 length of edge from fillet point
-static void getPointOnEdge(const FeaturePtr theFeature,
-                           const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
-                           std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
-/// Get distance from point to feature
-static double getProjectionDistance(const FeaturePtr theFeature,
-                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
-
-/// Get coincide edges for fillet
-static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
-
-SketchPlugin_ConstraintFillet::SketchPlugin_ConstraintFillet()
-: myListOfPointsChangedInCode(false),
-  myRadiusChangedByUser(false),
-  myRadiusChangedInCode(false),
-  myRadiusInitialized(false)
-{
-}
-
-void SketchPlugin_ConstraintFillet::initAttributes()
-{
-  data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
-  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(),
-                       ModelAPI_AttributeRefAttrList::typeId());
-}
-
-void SketchPlugin_ConstraintFillet::execute()
-{
-  std::shared_ptr<ModelAPI_Data> aData = data();
-
-  // Check the base objects are initialized.
-  AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
-    aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
-  if(!aPointsRefList->isInitialized()) {
-    setError("Error: List of points is not initialized.");
-    return;
-  }
-
-  // Get fillet radius.
-  double aFilletRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-    aData->attribute(SketchPlugin_Constraint::VALUE()))->value();
-
-  // Wait all constraints being created, then send update events
-  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
-  if (isUpdateFlushed)
-    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
-
-  for(std::set<AttributePtr>::iterator aPointsIter = myNewPoints.begin();
-      aPointsIter != myNewPoints.end();
-      ++aPointsIter) {
-    AttributePtr aPointAttr = *aPointsIter;
-    std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2d =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr);
-    if(!aFilletPoint2d.get()) {
-      setError("Error: One of the selected points is empty.");
-      return;
-    }
-    std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2d->pnt();
-
-    // Obtain base lines for fillet.
-    bool anIsNeedNewObjects = true;
-    FilletFeatures aFilletFeatures;
-    std::map<AttributePtr, FilletFeatures>::iterator aPrevPointsIter =
-      myPointFeaturesMap.find(aPointAttr);
-    if(aPrevPointsIter != myPointFeaturesMap.end()) {
-      anIsNeedNewObjects = false;
-      aFilletFeatures = aPrevPointsIter->second;
-    }
-    FeaturePtr aBaseEdgeA, aBaseEdgeB;
-    if(!anIsNeedNewObjects) {
-      aBaseEdgeA = aFilletFeatures.baseEdgesState.front().first;
-      aBaseEdgeB = aFilletFeatures.baseEdgesState.back().first;
-    } else {
-      // Obtain constraint coincidence for the fillet point.
-      FeaturePtr aConstraintCoincidence;
-      const std::set<AttributePtr>& aRefsList = aFilletPoint2d->owner()->data()->refsToMe();
-      for(std::set<AttributePtr>::const_iterator
-          anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
-        FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
-        if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
-          AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
-          AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
-          if(anAttrRefA.get() && !anAttrRefA->isObject()) {
-            AttributePtr anAttrA = anAttrRefA->attr();
-            if(aFilletPoint2d == anAttrA) {
-              aConstraintCoincidence = aConstrFeature;
-              break;
-            }
-          }
-          if(anAttrRefB.get() && !anAttrRefB->isObject()) {
-            AttributePtr anAttrB = anAttrRefB->attr();
-            if(aFilletPoint2d == anAttrB) {
-              aConstraintCoincidence = aConstrFeature;
-              break;
-            }
-          }
-        }
-      }
-
-      if(!aConstraintCoincidence.get()) {
-        setError("Error: No coincident edges at one of the selected points.");
-        return;
-      }
-
-      // Get coincide edges.
-      std::set<FeaturePtr> aCoincides = getCoincides(aConstraintCoincidence);
-      if(aCoincides.size() != 2) {
-        setError("Error: One of the selected points does not have two suitable edges for fillet.");
-        return;
-      }
-
-      std::set<FeaturePtr>::iterator aLinesIt = aCoincides.begin();
-      aBaseEdgeA = *aLinesIt++;
-      aBaseEdgeB = *aLinesIt;
-
-      std::pair<FeaturePtr, bool> aBasePairA =
-        std::make_pair(aBaseEdgeA,
-                       aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
-      std::pair<FeaturePtr, bool> aBasePairB =
-        std::make_pair(aBaseEdgeB,
-                       aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
-      aFilletFeatures.baseEdgesState.push_back(aBasePairA);
-      aFilletFeatures.baseEdgesState.push_back(aBasePairB);
-    }
-
-    if(!aBaseEdgeA.get() || !aBaseEdgeB.get()) {
-      setError("Error: One of the base edges is empty.");
-      return;
-    }
-
-    // Create new edges and arc if needed.
-    FeaturePtr aResultEdgeA, aResultEdgeB, aResultArc;
-    if(!anIsNeedNewObjects) {
-      // Obtain features from the list.
-      std::list<FeaturePtr>::iterator aResultEdgesIt = aFilletFeatures.resultEdges.begin();
-      aResultEdgeA = *aResultEdgesIt++;
-      aResultEdgeB = *aResultEdgesIt++;
-      aResultArc = *aResultEdgesIt;
-    } else {
-      // Copy edges and create arc.
-      aResultEdgeA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeA, sketch());
-      aResultEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false);
-      aResultEdgeB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeB, sketch());
-      aResultEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false);
-      aResultArc = sketch()->addFeature(SketchPlugin_Arc::ID());
-
-      aFilletFeatures.resultEdges.push_back(aResultEdgeA);
-      aFilletFeatures.resultEdges.push_back(aResultEdgeB);
-      aFilletFeatures.resultEdges.push_back(aResultArc);
-    }
-
-    // Calculate arc attributes
-    static const int aNbFeatures = 2;
-    FeaturePtr aBaseFeatures[aNbFeatures] = {aBaseEdgeA, aBaseEdgeB};
-    FeaturePtr aResultFeatures[aNbFeatures] = {aResultEdgeA, aResultEdgeB};
-    // tangent directions of the features in coincident point
-    std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
-    bool isStart[aNbFeatures]; // indicates which point the features share
-    // first pair of points relate to first feature, second pair -  to second
-    std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
-    std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features
-    for (int i = 0; i < aNbFeatures; i++) {
-      std::string aStartAttr, aEndAttr;
-      if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
-        aStartAttr = SketchPlugin_Line::START_ID();
-        aEndAttr = SketchPlugin_Line::END_ID();
-      } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
-        aStartAttr = SketchPlugin_Arc::START_ID();
-        aEndAttr = SketchPlugin_Arc::END_ID();
-      } else { // wrong argument
-        setError("Error: One of the points has wrong coincide feature");
-        return;
-      }
-      aFeatAttributes[2*i] = aStartAttr;
-      aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aBaseFeatures[i]->attribute(aStartAttr))->pnt();
-      aFeatAttributes[2*i+1] = aEndAttr;
-      aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aBaseFeatures[i]->attribute(aEndAttr))->pnt();
-    }
-    for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
-      for (int j = 0; j < 2; j++) // loop on start-end of each feature
-        if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
-          isStart[aFeatInd] = (j==0);
-          break;
-        }
-    }
-    // tangent directions of the features
-    for (int i = 0; i < aNbFeatures; i++) {
-      std::shared_ptr<GeomAPI_XY> aDir;
-      if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
-        aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
-        if (!isStart[i])
-          aDir = aDir->multiplied(-1.0);
-      } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
-        std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aResultFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-        aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
-        aDir = aDir->decreased(aCenterPoint->xy());
-
-        double x = aDir->x();
-        double y = aDir->y();
-        aDir->setX(-y);
-        aDir->setY(x);
-        if (isStart[i] ==
-            std::dynamic_pointer_cast<SketchPlugin_Arc>(aBaseFeatures[i])->isReversed())
-          aDir = aDir->multiplied(-1.0);
-      }
-      aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
-    }
-
-    // By default, the start point of fillet arc is connected to FeatureA,
-    // and the end point - to FeatureB. But when the angle between TangentDirA and
-    // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
-    double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
-    // where A and B - angles between corresponding tanget direction and the X axis
-    bool isReversed = cosBA > 0.0;
-
-    // Calculate fillet arc parameters
-    std::shared_ptr<GeomAPI_XY> aCenter, aTangentPntA, aTangentPntB;
-    calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, aFilletRadius,
-                          isStart, aCenter, aTangentPntA, aTangentPntB);
-    if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) {
-      setError("Can not create fillet with the specified parameters.");
-      return;
-    }
-    // update features
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->
-      setValue(aTangentPntA->x(), aTangentPntA->y());
-    aResultEdgeA->execute();
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->
-      setValue(aTangentPntB->x(), aTangentPntB->y());
-    aResultEdgeB->execute();
-    // 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 = aResultArc->data()->blockSendAttributeUpdated(true);
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y());
-    if(isReversed) {
-      std::shared_ptr<GeomAPI_XY> aTmp = aTangentPntA;
-      aTangentPntA = aTangentPntB;
-      aTangentPntB = aTmp;
-    }
-    std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aResultArc->attribute(SketchPlugin_Arc::START_ID()));
-    std::shared_ptr<GeomDataAPI_Point2D> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aResultArc->attribute(SketchPlugin_Arc::END_ID()));
-    if(aStartPoint->isInitialized() && aEndPoint->isInitialized() &&
-      (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance ||
-       aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) {
-      std::dynamic_pointer_cast<SketchPlugin_Arc>(aResultArc)->setReversed(false);
-    }
-    aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y());
-    aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y());
-    aResultArc->data()->blockSendAttributeUpdated(aWasBlocked);
-    aResultArc->execute();
-
-    if(anIsNeedNewObjects) {
-      // Create list of additional constraints:
-      // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc
-      // 1.1. coincidence
-      FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
-      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-      aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID()));
-      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-      int aFeatInd = isReversed ? 1 : 0;
-      int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1);
-      aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
-      recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(),
-                            aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
-      aConstraint->execute();
-      aFilletFeatures.resultConstraints.push_back(aConstraint);
-      ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-      // 1.2. coincidence
-      aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
-      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-      aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID()));
-      aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-      aFeatInd = isReversed ? 0 : 1;
-      anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1);
-      aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
-      recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(),
-                            aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]);
-      aConstraint->execute();
-      aFilletFeatures.resultConstraints.push_back(aConstraint);
-      ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-      // 2. Fillet arc radius
-      //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID());
-      //aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      //    aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-      //aRefAttr->setObject(aNewArc->lastResult());
-      //std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      //    aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius);
-      //std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      //    aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue(
-      //    isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]);
-      //aConstraint->execute();
-      //myProducedFeatures.push_back(aConstraint);
-      //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-      // 3. Tangency of fillet arc and features
-      for (int i = 0; i < aNbFeatures; i++) {
-        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-        aRefAttr->setObject(aResultArc->lastResult());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-        bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID();
-        aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() :
-                                    aResultFeatures[i]->firstResult());
-        aConstraint->execute();
-        aFilletFeatures.resultConstraints.push_back(aConstraint);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-      }
-      // 4. Coincidence of free boundaries of base and copied features
-      for (int i = 0; i < aNbFeatures; i++) {
-        anAttrInd = 2*i + (isStart[i] ? 1 : 0);
-        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-        aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-        aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
-        aFilletFeatures.resultConstraints.push_back(aConstraint);
-      }
-      // 4.1. Additional tangency constraints when the fillet is based on arcs.
-      //      It is used to verify the created arc will be placed on a source.
-      for (int i = 0; i < aNbFeatures; ++i) {
-        if (aResultFeatures[i]->getKind() != SketchPlugin_Arc::ID())
-          continue;
-        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-        aRefAttr->setObject(aBaseFeatures[i]->lastResult());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-        aRefAttr->setObject(aResultFeatures[i]->lastResult());
-        aConstraint->execute();
-        aFilletFeatures.resultConstraints.push_back(aConstraint);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-      }
-      // 5. Tangent points should be placed on the base features
-      for (int i = 0; i < aNbFeatures; i++) {
-        anAttrInd = 2*i + (isStart[i] ? 0 : 1);
-        aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
-        aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
-        aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
-        aRefAttr->setObject(aBaseFeatures[i]->lastResult());
-        aFilletFeatures.resultConstraints.push_back(aConstraint);
-      }
-      // make base features auxiliary
-      aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
-      aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
-
-      // exchange the naming IDs of newly created and old line that become auxiliary
-      sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA);
-      sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB);
-
-      // store point and features in the map.
-      myPointFeaturesMap[aPointAttr] = aFilletFeatures;
-    } else {
-      // Update radius value
-      int aNbSubs = sketch()->numberOfSubs();
-      FeaturePtr aSubFeature;
-      for (int aSub = 0; aSub < aNbSubs; aSub++) {
-        aSubFeature = sketch()->subFeature(aSub);
-        if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID())
-          continue;
-        AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
-        if (!aRefAttr || !aRefAttr->isObject())
-          continue;
-        FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
-        if (aFeature == aResultArc) {
-          AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-            aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
-          aRadius->setValue(aFilletRadius);
-          break;
-        }
-      }
-    }
-  }
-
-  // Send events to update the sub-features by the solver.
-  if(isUpdateFlushed) {
-    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
-  }
-}
-
-void SketchPlugin_ConstraintFillet::attributeChanged(const std::string& theID)
-{
-  if(theID == SketchPlugin_Constraint::ENTITY_A()) {
-    if(myListOfPointsChangedInCode) {
-      return;
-    }
-
-    // Clear results.
-    clearResults();
-
-    // Clear list of new points.
-    myNewPoints.clear();
-
-    // Get list of points for fillets and current radius.
-    AttributeRefAttrListPtr aRefListOfFilletPoints =
-      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
-      data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
-    AttributeDoublePtr aRadiusAttribute = real(VALUE());
-    int aListSize = aRefListOfFilletPoints->size();
-    if(aListSize == 0 && !myRadiusChangedByUser) {
-      // If list is empty reset radius to zero (if it was not changed by user).
-      myRadiusChangedInCode = true;
-      aRadiusAttribute->setValue(0);
-      myRadiusChangedInCode = false;
-      return;
-    }
-
-    // Iterate over points to get base lines an calculate radius for fillets.
-    double aMinimumRadius = 0;
-    std::list<std::pair<ObjectPtr, AttributePtr>>
-      aSelectedPointsList = aRefListOfFilletPoints->list();
-    std::list<std::pair<ObjectPtr, AttributePtr>>::iterator anIter = aSelectedPointsList.begin();
-    std::set<AttributePtr> aPointsToSkeep;
-    for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) {
-      AttributePtr aFilletPointAttr = (*anIter).second;
-      std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFilletPointAttr);
-      if(!aFilletPoint2D.get()) {
-        myNewPoints.clear();
-        setError("Error: One of the selected points is invalid.");
-        return;
-      }
-
-      // If point or coincident point is already in list remove it from attribute.
-      if(aPointsToSkeep.find(aFilletPointAttr) != aPointsToSkeep.end()) {
-        myListOfPointsChangedInCode = true;
-        aRefListOfFilletPoints->remove(aFilletPointAttr);
-        myListOfPointsChangedInCode = false;
-        continue;
-      }
-
-      // Obtain constraint coincidence for the fillet point.
-      FeaturePtr aConstraintCoincidence;
-      const std::set<AttributePtr>& aRefsList = aFilletPointAttr->owner()->data()->refsToMe();
-      for(std::set<AttributePtr>::const_iterator
-          anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
-        FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
-        if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
-          AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
-          AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-            aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
-          if(anAttrRefA.get()) {
-            AttributePtr anAttrA = anAttrRefA->attr();
-            if(aFilletPointAttr == anAttrA) {
-              aConstraintCoincidence = aConstrFeature;
-              break;
-            }
-          }
-          if(anAttrRefB.get()) {
-            AttributePtr anAttrB = anAttrRefB->attr();
-            if(aFilletPointAttr == anAttrB) {
-              aConstraintCoincidence = aConstrFeature;
-              break;
-            }
-          }
-        }
-      }
-
-      if(!aConstraintCoincidence.get()) {
-        myNewPoints.clear();
-        setError("Error: No coincident edges at one of the selected points.");
-        return;
-      }
-
-      // Get coincides from constraint.
-      std::set<FeaturePtr> aCoincides;
-
-
-      SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
-                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
-                                           aCoincides);
-      SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
-                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
-                                           aCoincides);
-
-      // Remove points from set of coincides.
-      // Also get all attributes which is equal to this point to exclude it.
-      std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
-      std::set<FeaturePtr> aNewSetOfCoincides;
-      for(std::set<FeaturePtr>::iterator
-          anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
-        std::string aFeatureKind = (*anIt)->getKind();
-        if(aFeatureKind == SketchPlugin_Point::ID()) {
-          AttributePtr anAttr = (*anIt)->attribute(SketchPlugin_Point::COORD_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
-          if(aPoint2D.get() && aFilletPnt2d->isEqual(aPoint2D->pnt())) {
-            aPointsToSkeep.insert(anAttr);
-          }
-        } else if(aFeatureKind == SketchPlugin_Line::ID()) {
-          AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Line::START_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPointStart2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
-          if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
-            aPointsToSkeep.insert(anAttrStart);
-          }
-          AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEnd);
-          if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) {
-            aPointsToSkeep.insert(anAttrEnd);
-          }
-          aNewSetOfCoincides.insert(*anIt);
-        } else if(aFeatureKind == SketchPlugin_Arc::ID() ) {
-          AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
-          if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) {
-            aPointsToSkeep.insert(anAttrCenter);
-            continue;
-          }
-          AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPointStart2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
-          if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
-            aPointsToSkeep.insert(anAttrStart);
-          }
-          AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID());
-          std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEnd);
-          if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) {
-            aPointsToSkeep.insert(anAttrEnd);
-          }
-          aNewSetOfCoincides.insert(*anIt);
-        }
-      }
-      aCoincides = aNewSetOfCoincides;
-
-      // If we still have more than two coincides remove auxilary entities from set of coincides.
-      if(aCoincides.size() > 2) {
-        aNewSetOfCoincides.clear();
-        for(std::set<FeaturePtr>::iterator
-            anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
-          if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
-            aNewSetOfCoincides.insert(*anIt);
-          }
-        }
-        aCoincides = aNewSetOfCoincides;
-      }
-
-      if(aCoincides.size() != 2) {
-        myNewPoints.clear();
-        setError("Error: One of the selected points does not have two suitable edges for fillet.");
-        return;
-      }
-
-      // Store base point for fillet.
-      aPointsToSkeep.insert(aFilletPointAttr);
-      myNewPoints.insert(aFilletPointAttr);
-
-      // Get base lines for fillet.
-      FeaturePtr anOldFeatureA, anOldFeatureB;
-      std::set<FeaturePtr>::iterator aLinesIt = aCoincides.begin();
-      anOldFeatureA = *aLinesIt++;
-      anOldFeatureB = *aLinesIt;
-
-      // Getting radius value if it was not changed by user.
-      if(!myRadiusChangedByUser) {
-        // Getting points located at 1/3 of edge length from fillet point.
-        std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
-        std::shared_ptr<GeomAPI_Pnt2d> aPntA, aPntB;
-        getPointOnEdge(anOldFeatureA, aFilletPnt2d, aPntA);
-        getPointOnEdge(anOldFeatureB, aFilletPnt2d, aPntB);
-
-        /// Getting distances.
-        double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA);
-        double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB);
-        double aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0;
-        aMinimumRadius = aMinimumRadius == 0 ? aRadius :
-          aRadius < aMinimumRadius ? aRadius : aMinimumRadius;
-      }
-    }
-
-    // Set new default radius if it was not changed by user.
-    if(!myRadiusChangedByUser) {
-      myRadiusChangedInCode = true;
-      aRadiusAttribute->setValue(aMinimumRadius);
-      myRadiusChangedInCode = false;
-    }
-
-  } else if(theID == SketchPlugin_Constraint::VALUE()) {
-    if(myRadiusInitialized && !myRadiusChangedInCode) {
-      myRadiusChangedByUser = true;
-    }
-    if(!myRadiusInitialized) {
-      myRadiusInitialized = true;
-    }
-  }
-}
-
-AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePrevious)
-{
-  if (!sketch())
-    return thePrevious;
-
-  AISObjectPtr anAIS = thePrevious;
-  /// TODO: Equal constraint presentation should be put here
-  return anAIS;
-}
-
-bool SketchPlugin_ConstraintFillet::isMacro() const
-{
-  return true;
-}
-
-void SketchPlugin_ConstraintFillet::clearResults()
-{
-  // Clear auxiliary flag on initial objects.
-  for(std::map<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
-      aPointsIter != myPointFeaturesMap.end();) {
-    const FilletFeatures& aFilletFeatures = aPointsIter->second;
-    std::list<std::pair<FeaturePtr, bool>>::const_iterator aFeatureIt;
-    for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin();
-        aFeatureIt != aFilletFeatures.baseEdgesState.cend();
-        ++aFeatureIt) {
-      aFeatureIt->first->boolean(
-        SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second);
-    }
-    ++aPointsIter;
-  }
-
-  // And remove all produced features.
-  DocumentPtr aDoc = sketch()->document();
-  for(std::map<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
-      aPointsIter != myPointFeaturesMap.end();) {
-    // Remove all produced constraints.
-    const FilletFeatures& aFilletFeatures = aPointsIter->second;
-    std::list<FeaturePtr>::const_iterator aFeatureIt;
-    for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin();
-        aFeatureIt != aFilletFeatures.resultConstraints.cend();
-        ++aFeatureIt) {
-      aDoc->removeFeature(*aFeatureIt);
-    }
-
-    // Remove all result edges.
-    for(aFeatureIt = aFilletFeatures.resultEdges.cbegin();
-        aFeatureIt != aFilletFeatures.resultEdges.cend();
-        ++aFeatureIt) {
-      aDoc->removeFeature(*aFeatureIt);
-    }
-
-    // Remove point from map.
-    myPointFeaturesMap.erase(aPointsIter++);
-  }
-};
-
-
-// =========   Auxiliary functions   =================
-void recalculateAttributes(FeaturePtr theNewArc,  const std::string& theNewArcAttribute,
-                           FeaturePtr theFeature, const std::string& theFeatureAttribute)
-{
-  std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theNewArc->attribute(theNewArcAttribute))->pnt();
-  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
-}
-
-/// \brief Find intersections of lines shifted along normal direction
-void possibleFilletCenterLineLine(
-    std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
-    std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
-  std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
-  std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
-  std::shared_ptr<GeomAPI_XY> aPntA, aPntB;
-  double aDet = theDirA->cross(theDirB);
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius));
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius));
-      double aVX = aDirAT->xy()->dot(aPntA);
-      double aVY = aDirBT->xy()->dot(aPntB);
-      std::shared_ptr<GeomAPI_XY> aPoint(new GeomAPI_XY(
-          (theDirB->x() * aVX - theDirA->x() * aVY) / aDet,
-          (theDirB->y() * aVX - theDirA->y() * aVY) / aDet));
-      theCenters.push_back(aPoint);
-    }
-  }
-}
-
-/// \brief Find intersections of line shifted along normal direction in both sides
-///        and a circle with extended radius
-void possibleFilletCenterLineArc(
-    std::shared_ptr<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
-    std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
-  std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
-  std::shared_ptr<GeomAPI_XY> aPnt;
-  double aDirNorm2 = theDirLine->dot(theDirLine);
-  double aRad = 0.0;
-  double aDirX = theDirLine->x();
-  double aDirX2 = theDirLine->x() * theDirLine->x();
-  double aDirY2 = theDirLine->y() * theDirLine->y();
-  double aDirXY = theDirLine->x() * theDirLine->y();
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius));
-    double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc));
-    double aCoeff2 = aCoeff * aCoeff;
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aRad = theRadiusArc + aStepB * theRadius;
-      double aD = aRad * aRad * aDirNorm2 - aCoeff2;
-      if (aD < 0.0)
-        continue;
-      double aDs = sqrt(aD);
-      double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2;
-      double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2;
-      double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
-          aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2;
-      double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
-          aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2;
-
-      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
-      theCenters.push_back(aPoint1);
-      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
-      theCenters.push_back(aPoint2);
-    }
-  }
-}
-
-/// \brief Find intersections of two circles with extended radii
-void possibleFilletCenterArcArc(
-    std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
-    std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
-    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
-  std::shared_ptr<GeomAPI_XY> aCenterDir = theCenterB->decreased(theCenterA);
-  double aCenterDist2 = aCenterDir->dot(aCenterDir);
-  double aCenterDist = sqrt(aCenterDist2);
-
-  double aRadA, aRadB;
-  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
-    aRadA = theRadiusA + aStepA * theRadius;
-    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
-      aRadB = theRadiusB + aStepB * theRadius;
-      if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist)
-        continue; // there is no intersections
-
-      double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist);
-      double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist);
-
-      double x1 = theCenterA->x() +
-        (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist;
-      double y1 = theCenterA->y() +
-        (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist;
-
-      double x2 = theCenterA->x() +
-        (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist;
-      double y2 = theCenterA->y() +
-        (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist;
-
-      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
-      theCenters.push_back(aPoint1);
-      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
-      theCenters.push_back(aPoint2);
-    }
-  }
-}
-
-void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
-                           double theRadius, bool theNotInversed[2],
-                           std::shared_ptr<GeomAPI_XY>& theCenter,
-                           std::shared_ptr<GeomAPI_XY>& theTangentA,
-                           std::shared_ptr<GeomAPI_XY>& theTangentB)
-{
-  static const int aNbFeatures = 2;
-  FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
-  std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
-  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
-
-  for (int i = 0; i < aNbFeatures; i++) {
-    if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
-      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
-      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
-    } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
-      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
-      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
-      aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
-    } else
-      return;
-    aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
-        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
-        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
-    aEnd[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
-        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) :
-        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()));
-  }
-
-  if (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Dir2d> aDir[2];
-    std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
-    for (int i = 0; i < aNbFeatures; i++) {
-      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
-      aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
-    }
-
-    // get and filter possible centers
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1],
-                                 theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt));
-      theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot));
-      if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0)
-        continue; // incorrect position
-      aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt));
-      theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot));
-      if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0)
-        continue; // incorrect position
-      // the center is found, stop searching
-      theCenter = *anIt;
-      return;
-    }
-  } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Line::ID()) ||
-      (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Arc::ID())) {
-    int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1;
-    double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]);
-    std::shared_ptr<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
-    std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
-
-    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
-    std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd])));
-    double anArcAngle = aEndArcDir->angle(aStartArcDir);
-
-    // get possible centers and filter them
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd],
-                                anArcRadius, theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    // the line is forward into the arc
-    double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy());
-    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
-    // The possible centers are ranged by their positions.
-    // If the point is not satisfy one of criteria, the weight is decreased with penalty.
-    int aBestWeight = 0;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      int aWeight = 2;
-      aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt));
-      aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot));
-      // Check the point is placed on the correct arc (penalty if false)
-      if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc)
-        aWeight -= 1;
-      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd])));
-      double aCurAngle = aCurDir->angle(aStartArcDir);
-      if (anArcAngle < 0.0) aCurAngle *= -1.0;
-      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle))
-        continue;
-      if (aWeight > aBestWeight)
-        aBestWeight = aWeight;
-      else if (aWeight < aBestWeight ||
-               aStart[aLineInd]->distance(*anIt) >
-               aStart[aLineInd]->distance(theCenter)) // <-- take closer point
-        continue;
-      // the center is found, stop searching
-      theCenter = *anIt;
-      anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius));
-      if (theFeatureA->getKind() == SketchPlugin_Line::ID()) {
-        theTangentA = aLineTgPoint;
-        theTangentB = anArcTgPoint;
-      } else {
-        theTangentA = anArcTgPoint;
-        theTangentB = aLineTgPoint;
-      }
-      //return;
-    }
-  } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
-      theFeatureB->getKind() == SketchPlugin_Arc::ID()) {
-    double anArcRadius[aNbFeatures];
-    double anArcAngle[aNbFeatures];
-    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
-    for (int i = 0; i < aNbFeatures; i++) {
-      anArcRadius[i] = aStart[i]->distance(aCenter[i]);
-      aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
-      std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
-      anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]);
-    }
-
-    // get and filter possible centers
-    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
-    possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1],
-                               anArcRadius[1], theRadius, aSuspectCenters);
-    double aDot = 0.0;
-    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
-    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
-    for (; anIt != aSuspectCenters.end(); anIt++) {
-      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
-          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0])));
-      double aCurAngle = aCurDir->angle(aStartArcDir[0]);
-      if (anArcAngle[0] < 0.0) aCurAngle *= -1.0;
-      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0]))
-        continue; // incorrect position
-      theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0]));
-
-      aCurDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1])));
-      aCurAngle = aCurDir->angle(aStartArcDir[1]);
-      if (anArcAngle[1] < 0.0) aCurAngle *= -1.0;
-      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1]))
-        continue; // incorrect position
-      theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1]));
-
-      // the center is found, stop searching
-      theCenter = *anIt;
-      return;
-    }
-  }
-}
-
-void getPointOnEdge(const FeaturePtr theFeature,
-                    const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
-                    std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
-  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-    if(aPntStart->distance(theFilletPoint) > 1.e-7) {
-      aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-      aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    }
-    thePoint.reset(
-      new GeomAPI_Pnt2d(aPntStart->xy()->added(
-      aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) );
-  } else {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntTemp;
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-    if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) {
-      aPntTemp = aPntStart;
-      aPntStart = aPntEnd;
-      aPntEnd = aPntTemp;
-    }
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
-    double aStartParameter(0), anEndParameter(0);
-    aCirc->parameter(aPntStart, paramTolerance, aStartParameter);
-    aCirc->parameter(aPntEnd, paramTolerance, anEndParameter);
-    if(aPntStart->distance(theFilletPoint) > tolerance) {
-      double aTmpParameter = aStartParameter;
-      aStartParameter = anEndParameter;
-      anEndParameter = aTmpParameter;
-    }
-    double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0;
-    aCirc->D0(aPntParameter, thePoint);
-  }
-}
-
-double getProjectionDistance(const FeaturePtr theFeature,
-                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint)
-{
-  std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
-  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
-    aProjectPnt = aLin->project(thePoint);
-  } else {
-    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
-    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
-    aProjectPnt = aCirc->project(thePoint);
-  }
-  if(aProjectPnt.get()) {
-    return aProjectPnt->distance(thePoint);
-  }
-  return -1;
-}
-
-std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
-{
-  std::set<FeaturePtr> aCoincides;
-
-  std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt =
-    SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
-
-  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
-                                       SketchPlugin_ConstraintCoincidence::ENTITY_A(),
-                                       aCoincides);
-  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
-                                       SketchPlugin_ConstraintCoincidence::ENTITY_B(),
-                                       aCoincides);
-
-  // Remove points from set of coincides.
-  std::set<FeaturePtr> aNewSetOfCoincides;
-  for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
-    if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
-      aNewSetOfCoincides.insert(*anIt);
-    } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
-      AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
-      std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
-      if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
-        continue;
-      }
-      aNewSetOfCoincides.insert(*anIt);
-    }
-  }
-  aCoincides = aNewSetOfCoincides;
-
-  // If we still have more than two coincides remove auxilary entities from set of coincides.
-  if(aCoincides.size() > 2) {
-    aNewSetOfCoincides.clear();
-    for(std::set<FeaturePtr>::iterator
-        anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
-      if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
-        aNewSetOfCoincides.insert(*anIt);
-      }
-    }
-    aCoincides = aNewSetOfCoincides;
-  }
-
-  return aCoincides;
-}
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintFillet.h b/src/SketchPlugin/SketchPlugin_ConstraintFillet.h
deleted file mode 100644 (file)
index d860688..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
-
-// File:    SketchPlugin_ConstraintFillet.h
-// Created: 19 Mar 2015
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchPlugin_ConstraintFillet_H_
-#define SketchPlugin_ConstraintFillet_H_
-
-#include "SketchPlugin.h"
-#include <SketchPlugin_Sketch.h>
-#include "SketchPlugin_ConstraintBase.h"
-
-/** \class SketchPlugin_ConstraintFillet
- *  \ingroup Plugins
- *  \brief Feature for creation of a new constraint filleting two objects which have 
- *  coincident point
- *
- *  This constraint has three attributes:
- *  SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() 
- *  for the filleting objects;
- *  SketchPlugin_Constraint::VALUE() contains radius of filleting circular arc
- *
- *  Also the constraint has attribute SketchPlugin_Constraint::ENTITY_C()
- *  which contains created list objects forming the fillet
- */
-class SketchPlugin_ConstraintFillet : public SketchPlugin_ConstraintBase
-{
- public:
-   /// \struct Struct to store base edges with states, result edges and constraints.
-   struct FilletFeatures {
-     /// list of objects the fillet is based and its states
-     std::list<std::pair<FeaturePtr, bool>> baseEdgesState;
-     std::list<FeaturePtr> resultEdges; ///< list of result edges
-     std::list<FeaturePtr> resultConstraints; ///< list of constraints provided by the fillet
-   };
-
-  /// Fillet constraint kind
-  inline static const std::string& ID()
-  {
-    static const std::string MY_CONSTRAINT_FILLET_ID("SketchConstraintFillet");
-    return MY_CONSTRAINT_FILLET_ID;
-  }
-  /// \brief Returns the kind of a feature
-  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
-  {
-    static std::string MY_KIND = SketchPlugin_ConstraintFillet::ID();
-    return MY_KIND;
-  }
-
-  /// \brief Creates a new part document if needed
-  SKETCHPLUGIN_EXPORT virtual void execute();
-
-  /// \brief Request for initialization of data model of the feature: adding all attributes
-  SKETCHPLUGIN_EXPORT virtual void initAttributes();
-
-  /// Called on change of any argument-attribute of this object
-  /// \param theID identifier of changed attribute
-  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
-
-  /// Returns the AIS preview
-  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
-
-  /// Reimplemented from ModelAPI_Feature::isMacro().
-  /// \returns true
-  SKETCHPLUGIN_EXPORT virtual bool isMacro() const;
-
-  /// \brief Use plugin manager for features creation
-  SketchPlugin_ConstraintFillet();
-
-  /// \return map of base points and features;
-  SKETCHPLUGIN_EXPORT const std::map<AttributePtr, FilletFeatures> pointsFeaturesMap() const {
-    return myPointFeaturesMap;
-  };
-
-private:
-  /// \ Removes all produced features and restore base edges.
-  void clearResults();
-
-private:
-  std::set<AttributePtr> myNewPoints; ///< set of new points
-
-  /// map of point and features for fillet
-  std::map<AttributePtr, FilletFeatures> myPointFeaturesMap;
-  bool myListOfPointsChangedInCode; ///< flag to track that list of points changed in code
-  bool myRadiusChangedByUser; ///< flag to track that radius changed by user
-  bool myRadiusChangedInCode; ///< flag to track that radius changed in code
-  bool myRadiusInitialized; /// < flag to track that radius initialized
-};
-
-#endif
diff --git a/src/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp
new file mode 100644 (file)
index 0000000..9a16340
--- /dev/null
@@ -0,0 +1,796 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_Fillet.cpp
+// Created: 19 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include "SketchPlugin_Fillet.h"
+
+#include "SketchPlugin_Arc.h"
+#include "SketchPlugin_Line.h"
+#include "SketchPlugin_Point.h"
+#include "SketchPlugin_Sketch.h"
+#include "SketchPlugin_ConstraintEqual.h"
+#include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_ConstraintLength.h"
+#include "SketchPlugin_ConstraintTangent.h"
+#include "SketchPlugin_ConstraintRadius.h"
+#include "SketchPlugin_Tools.h"
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <Events_Loop.h>
+
+#include <math.h>
+
+const double tolerance = 1.e-7;
+const double paramTolerance = 1.e-4;
+
+/// \brief Attract specified point on theNewArc to the attribute of theFeature
+static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
+  FeaturePtr theFeature, const std::string& theFeatureAttribute);
+
+/// \brief Calculates center of fillet arc and coordinates of tangency points
+static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
+                                  double theRadius, bool theNotInversed[2],
+                                  std::shared_ptr<GeomAPI_XY>& theCenter,
+                                  std::shared_ptr<GeomAPI_XY>& theTangentA,
+                                  std::shared_ptr<GeomAPI_XY>& theTangentB);
+
+/// Get point on 1/3 length of edge from fillet point
+static void getPointOnEdge(const FeaturePtr theFeature,
+                           const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
+                           std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+/// Get distance from point to feature
+static double getProjectionDistance(const FeaturePtr theFeature,
+                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
+
+/// Get coincide edges for fillet
+static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
+
+static std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
+                                                 const AttributePtr theAttribute);
+
+SketchPlugin_Fillet::SketchPlugin_Fillet()
+: myFilletCreated(false)
+{
+}
+
+void SketchPlugin_Fillet::initAttributes()
+{
+  data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+void SketchPlugin_Fillet::execute()
+{
+  // Wait all constraints being created, then send update events
+  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+  if (isUpdateFlushed)
+    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+
+  // Create arc feature.
+  FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID());
+
+  // Set arc attributes.
+  bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
+                                                                      myCenterXY->y());
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
+  std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
+  if(aStartPoint->isInitialized() && aEndPoint->isInitialized()
+      && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance
+      || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) {
+    std::dynamic_pointer_cast<SketchPlugin_Arc>(aFilletArc)->setReversed(false);
+  }
+  aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y());
+  aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y());
+  aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked);
+  aFilletArc->execute();
+
+  // Delete features with refs to points of edges.
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint1;
+  int aFeatInd1 = myIsReversed ? 1 : 0;
+  int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1);
+  aStartPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
+  std::set<FeaturePtr> aFeaturesToBeRemoved1 =
+    findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1);
+
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint2;
+  int aFeatInd2 = myIsReversed ? 0 : 1;
+  int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1);
+  aStartPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
+  std::set<FeaturePtr> aFeaturesToBeRemoved2 =
+    findFeaturesToRemove(myBaseFeatures[aFeatInd2], aStartPoint2);
+
+  aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end());
+  ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1);
+
+  // Update fillet edges.
+  recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
+                        myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]);
+  recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
+                        myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]);
+
+  // Create coincidence features.
+  FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+  AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
+  aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+  aRefAttr->setAttr(myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
+  aConstraint->execute();
+  ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+  aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+  aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
+  aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+  aRefAttr->setAttr(myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
+  aConstraint->execute();
+  ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+
+  // Create tangent features.
+  for (int i = 0; i < 2; i++) {
+    aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+    aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+    aRefAttr->setObject(aFilletArc->lastResult());
+    aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+    bool isArc = myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID();
+    aRefAttr->setObject(isArc ? myBaseFeatures[i]->lastResult() :
+                                myBaseFeatures[i]->firstResult());
+    aConstraint->execute();
+    ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+  }
+
+  // Send events to update the sub-features by the solver.
+  if(isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+  }
+
+  myFilletCreated = true;
+}
+
+AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
+{
+  if(myFilletCreated) {
+    return AISObjectPtr();
+  }
+
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    return AISObjectPtr();
+  }
+
+  // Get fillet point.
+  AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID());
+  if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject()) {
+    return AISObjectPtr();
+  }
+  std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
+  if (!aFilletPoint2D.get()) {
+    return AISObjectPtr();
+  }
+
+  // Obtain constraint coincidence for the fillet point.
+  FeaturePtr aConstraintCoincidence;
+  const std::set<AttributePtr>& aRefsList = aFilletPoint2D->owner()->data()->refsToMe();
+  for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
+      anIt != aRefsList.cend();
+      ++anIt) {
+    std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+    if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+      AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
+      if(anAttrRefA.get() && !anAttrRefA->isObject()) {
+        AttributePtr anAttrA = anAttrRefA->attr();
+        if(aFilletPoint2D == anAttrA) {
+          aConstraintCoincidence = aFeature;
+          break;
+        }
+      }
+      if(anAttrRefB.get() && !anAttrRefB->isObject()) {
+        AttributePtr anAttrB = anAttrRefB->attr();
+        if(aFilletPoint2D == anAttrB) {
+          aConstraintCoincidence = aFeature;
+          break;
+        }
+      }
+    }
+  }
+
+  if(!aConstraintCoincidence.get()) {
+    setError("Error: No coincident edges at selected point.");
+    return AISObjectPtr();
+  }
+
+  // Get coincide edges.
+  std::set<FeaturePtr> anEdgeFeatures = getCoincides(aConstraintCoincidence);
+  if(anEdgeFeatures.size() != 2) {
+    setError("Error: Selected point does not have two suitable edges for fillet.");
+    return AISObjectPtr();
+  }
+
+  FeaturePtr anEdgeFeature1, anEdgeFeature2;
+  std::set<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
+  anEdgeFeature1 = *aLinesIt++;
+  anEdgeFeature2 = *aLinesIt;
+
+  // Getting points located at 1/3 of edge length from fillet point.
+  std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aPnt1, aPnt2;
+  getPointOnEdge(anEdgeFeature1, aFilletPnt2d, aPnt1);
+  getPointOnEdge(anEdgeFeature2, aFilletPnt2d, aPnt2);
+
+  /// Getting distances.
+  double aDistance1 = getProjectionDistance(anEdgeFeature2, aPnt1);
+  double aDistance2 = getProjectionDistance(anEdgeFeature1, aPnt2);
+
+  // Calculate radius value for fillet.
+  double aRadius = aDistance1 < aDistance2 ? aDistance1 / 2.0 : aDistance2 / 2.0;
+
+  // Calculate arc attributes.
+  static const int aNbFeatures = 2;
+  myBaseFeatures[0] = anEdgeFeature1;
+  myBaseFeatures[1] = anEdgeFeature2;
+  // First pair of points relate to first feature, second pair -  to second.
+  std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2];
+  for (int i = 0; i < aNbFeatures; i++) {
+    std::string aStartAttr, aEndAttr;
+    if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
+      aStartAttr = SketchPlugin_Line::START_ID();
+      aEndAttr = SketchPlugin_Line::END_ID();
+    } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
+      aStartAttr = SketchPlugin_Arc::START_ID();
+      aEndAttr = SketchPlugin_Arc::END_ID();
+    } else { // Wrong argument.
+      setError("Error: One of the points has wrong coincide feature");
+      return AISObjectPtr();
+    }
+    myFeatAttributes[2*i] = aStartAttr;
+    aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      myBaseFeatures[i]->attribute(aStartAttr))->pnt();
+    myFeatAttributes[2*i+1] = aEndAttr;
+    aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      myBaseFeatures[i]->attribute(aEndAttr))->pnt();
+  }
+  for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) {
+    for (int j = 0; j < 2; j++) // loop on start-end of each feature
+      if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) {
+        myIsNotInversed[aFeatInd] = (j==0);
+        break;
+      }
+  }
+
+  calculateFilletCenter(anEdgeFeature1, anEdgeFeature2, aRadius,
+      myIsNotInversed, myCenterXY, myTangentXY1, myTangentXY2);
+
+  // Tangent directions of the features in coincident point.
+  std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
+  for (int i = 0; i < aNbFeatures; i++) {
+    std::shared_ptr<GeomAPI_XY> aDir;
+    if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) {
+      aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
+      if (!myIsNotInversed[i])
+        aDir = aDir->multiplied(-1.0);
+    } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) {
+      std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+      aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
+      aDir = aDir->decreased(aCenterPoint->xy());
+
+      double x = aDir->x();
+      double y = aDir->y();
+      aDir->setX(-y);
+      aDir->setY(x);
+      if (myIsNotInversed[i] ==
+          std::dynamic_pointer_cast<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
+        aDir = aDir->multiplied(-1.0);
+    }
+    aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
+  }
+
+  // By default, the start point of fillet arc is connected to FeatureA,
+  // and the end point - to FeatureB. But when the angle between TangentDirA and
+  // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
+  double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A),
+  // where A and B - angles between corresponding tanget direction and the X axis
+  myIsReversed = cosBA > 0.0;
+
+  if(myIsReversed) {
+    std::shared_ptr<GeomAPI_XY> aTmp = myTangentXY1;
+    myTangentXY1 = myTangentXY2;
+    myTangentXY2 = aTmp;
+  }
+
+  // Create arc for presentation.
+  std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
+  std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
+                                                          myTangentXY1->y()));
+  std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
+                                                          myTangentXY2->y()));
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+  std::shared_ptr<GeomAPI_Shape> anArcShape =
+      GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir());
+
+  AISObjectPtr anAISObject = thePrevious;
+  if(!anAISObject.get()) {
+    anAISObject = AISObjectPtr(new GeomAPI_AISObject);
+  }
+  anAISObject->createShape(anArcShape);
+  return anAISObject;
+}
+
+// =========   Auxiliary functions   =================
+void recalculateAttributes(FeaturePtr theNewArc,  const std::string& theNewArcAttribute,
+                           FeaturePtr theFeature, const std::string& theFeatureAttribute)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theNewArc->attribute(theNewArcAttribute))->pnt();
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
+}
+
+/// \brief Find intersections of lines shifted along normal direction
+void possibleFilletCenterLineLine(
+    std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
+    std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
+  std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
+  std::shared_ptr<GeomAPI_XY> aPntA, aPntB;
+  double aDet = theDirA->cross(theDirB);
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius));
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius));
+      double aVX = aDirAT->xy()->dot(aPntA);
+      double aVY = aDirBT->xy()->dot(aPntB);
+      std::shared_ptr<GeomAPI_XY> aPoint(new GeomAPI_XY(
+          (theDirB->x() * aVX - theDirA->x() * aVY) / aDet,
+          (theDirB->y() * aVX - theDirA->y() * aVY) / aDet));
+      theCenters.push_back(aPoint);
+    }
+  }
+}
+
+/// \brief Find intersections of line shifted along normal direction in both sides
+///        and a circle with extended radius
+void possibleFilletCenterLineArc(
+    std::shared_ptr<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
+    std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
+  std::shared_ptr<GeomAPI_XY> aPnt;
+  double aDirNorm2 = theDirLine->dot(theDirLine);
+  double aRad = 0.0;
+  double aDirX = theDirLine->x();
+  double aDirX2 = theDirLine->x() * theDirLine->x();
+  double aDirY2 = theDirLine->y() * theDirLine->y();
+  double aDirXY = theDirLine->x() * theDirLine->y();
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius));
+    double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc));
+    double aCoeff2 = aCoeff * aCoeff;
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aRad = theRadiusArc + aStepB * theRadius;
+      double aD = aRad * aRad * aDirNorm2 - aCoeff2;
+      if (aD < 0.0)
+        continue;
+      double aDs = sqrt(aD);
+      double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2;
+      double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2;
+      double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
+          aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2;
+      double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() -
+          aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2;
+
+      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+      theCenters.push_back(aPoint1);
+      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+      theCenters.push_back(aPoint2);
+    }
+  }
+}
+
+/// \brief Find intersections of two circles with extended radii
+void possibleFilletCenterArcArc(
+    std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
+    std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
+    double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+  std::shared_ptr<GeomAPI_XY> aCenterDir = theCenterB->decreased(theCenterA);
+  double aCenterDist2 = aCenterDir->dot(aCenterDir);
+  double aCenterDist = sqrt(aCenterDist2);
+
+  double aRadA, aRadB;
+  for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) {
+    aRadA = theRadiusA + aStepA * theRadius;
+    for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) {
+      aRadB = theRadiusB + aStepB * theRadius;
+      if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist)
+        continue; // there is no intersections
+
+      double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist);
+      double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist);
+
+      double x1 = theCenterA->x() +
+        (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist;
+      double y1 = theCenterA->y() +
+        (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist;
+
+      double x2 = theCenterA->x() +
+        (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist;
+      double y2 = theCenterA->y() +
+        (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist;
+
+      std::shared_ptr<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+      theCenters.push_back(aPoint1);
+      std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+      theCenters.push_back(aPoint2);
+    }
+  }
+}
+
+void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
+                           double theRadius, bool theNotInversed[2],
+                           std::shared_ptr<GeomAPI_XY>& theCenter,
+                           std::shared_ptr<GeomAPI_XY>& theTangentA,
+                           std::shared_ptr<GeomAPI_XY>& theTangentB)
+{
+  static const int aNbFeatures = 2;
+  FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
+  std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
+  std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
+
+  for (int i = 0; i < aNbFeatures; i++) {
+    if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
+      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
+      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
+    } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
+      aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
+      aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
+      aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
+    } else
+      return;
+    aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
+        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
+        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
+    aEnd[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
+        new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) :
+        new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()));
+  }
+
+  if (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Dir2d> aDir[2];
+    std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
+    for (int i = 0; i < aNbFeatures; i++) {
+      aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
+      aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
+    }
+
+    // get and filter possible centers
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1],
+                                 theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt));
+      theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot));
+      if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0)
+        continue; // incorrect position
+      aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt));
+      theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot));
+      if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0)
+        continue; // incorrect position
+      // the center is found, stop searching
+      theCenter = *anIt;
+      return;
+    }
+  } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Line::ID()) ||
+      (theFeatureA->getKind() == SketchPlugin_Line::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Arc::ID())) {
+    int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1;
+    double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]);
+    std::shared_ptr<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
+    std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
+
+    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
+    std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+        new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd])));
+    double anArcAngle = aEndArcDir->angle(aStartArcDir);
+
+    // get possible centers and filter them
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd],
+                                anArcRadius, theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    // the line is forward into the arc
+    double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy());
+    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
+    // The possible centers are ranged by their positions.
+    // If the point is not satisfy one of criteria, the weight is decreased with penalty.
+    int aBestWeight = 0;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      int aWeight = 2;
+      aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt));
+      aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot));
+      // Check the point is placed on the correct arc (penalty if false)
+      if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc)
+        aWeight -= 1;
+      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd])));
+      double aCurAngle = aCurDir->angle(aStartArcDir);
+      if (anArcAngle < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle))
+        continue;
+      if (aWeight > aBestWeight)
+        aBestWeight = aWeight;
+      else if (aWeight < aBestWeight ||
+               aStart[aLineInd]->distance(*anIt) >
+               aStart[aLineInd]->distance(theCenter)) // <-- take closer point
+        continue;
+      // the center is found, stop searching
+      theCenter = *anIt;
+      anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius));
+      if (theFeatureA->getKind() == SketchPlugin_Line::ID()) {
+        theTangentA = aLineTgPoint;
+        theTangentB = anArcTgPoint;
+      } else {
+        theTangentA = anArcTgPoint;
+        theTangentB = aLineTgPoint;
+      }
+      //return;
+    }
+  } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() &&
+      theFeatureB->getKind() == SketchPlugin_Arc::ID()) {
+    double anArcRadius[aNbFeatures];
+    double anArcAngle[aNbFeatures];
+    std::shared_ptr<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
+    for (int i = 0; i < aNbFeatures; i++) {
+      anArcRadius[i] = aStart[i]->distance(aCenter[i]);
+      aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
+      std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
+      anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]);
+    }
+
+    // get and filter possible centers
+    std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+    possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1],
+                               anArcRadius[1], theRadius, aSuspectCenters);
+    double aDot = 0.0;
+    std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
+    std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+    for (; anIt != aSuspectCenters.end(); anIt++) {
+      std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+          new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0])));
+      double aCurAngle = aCurDir->angle(aStartArcDir[0]);
+      if (anArcAngle[0] < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0]))
+        continue; // incorrect position
+      theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0]));
+
+      aCurDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1])));
+      aCurAngle = aCurDir->angle(aStartArcDir[1]);
+      if (anArcAngle[1] < 0.0) aCurAngle *= -1.0;
+      if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1]))
+        continue; // incorrect position
+      theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1]));
+
+      // the center is found, stop searching
+      theCenter = *anIt;
+      return;
+    }
+  }
+}
+
+void getPointOnEdge(const FeaturePtr theFeature,
+                    const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
+                    std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
+  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+    if(aPntStart->distance(theFilletPoint) > 1.e-7) {
+      aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+      aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    }
+    thePoint.reset(
+      new GeomAPI_Pnt2d(aPntStart->xy()->added(
+      aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) );
+  } else {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntTemp;
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+    if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) {
+      aPntTemp = aPntStart;
+      aPntStart = aPntEnd;
+      aPntEnd = aPntTemp;
+    }
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
+    double aStartParameter(0), anEndParameter(0);
+    aCirc->parameter(aPntStart, paramTolerance, aStartParameter);
+    aCirc->parameter(aPntEnd, paramTolerance, anEndParameter);
+    if(aPntStart->distance(theFilletPoint) > tolerance) {
+      double aTmpParameter = aStartParameter;
+      aStartParameter = anEndParameter;
+      anEndParameter = aTmpParameter;
+    }
+    double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0;
+    aCirc->D0(aPntParameter, thePoint);
+  }
+}
+
+double getProjectionDistance(const FeaturePtr theFeature,
+                             const std::shared_ptr<GeomAPI_Pnt2d> thePoint)
+{
+  std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
+  if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
+    aProjectPnt = aLin->project(thePoint);
+  } else {
+    std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
+    aProjectPnt = aCirc->project(thePoint);
+  }
+  if(aProjectPnt.get()) {
+    return aProjectPnt->distance(thePoint);
+  }
+  return -1;
+}
+
+std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
+{
+  std::set<FeaturePtr> aCoincides;
+
+  std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt =
+    SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence);
+
+  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
+                                       SketchPlugin_ConstraintCoincidence::ENTITY_A(),
+                                       aCoincides);
+  SketchPlugin_Tools::findCoincidences(theConstraintCoincidence,
+                                       SketchPlugin_ConstraintCoincidence::ENTITY_B(),
+                                       aCoincides);
+
+  // Remove points from set of coincides.
+  std::set<FeaturePtr> aNewSetOfCoincides;
+  for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+    std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
+      std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
+    if(aSketchEntity.get() && aSketchEntity->isCopy()) {
+      continue;
+    }
+    if((*anIt)->getKind() == SketchPlugin_Line::ID()) {
+      aNewSetOfCoincides.insert(*anIt);
+    } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
+      AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
+      std::shared_ptr<GeomDataAPI_Point2D> aPointCenter2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
+      if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) {
+        continue;
+      }
+      aNewSetOfCoincides.insert(*anIt);
+    }
+  }
+  aCoincides = aNewSetOfCoincides;
+
+  // If we still have more than two coincides remove auxilary entities from set of coincides.
+  if(aCoincides.size() > 2) {
+    aNewSetOfCoincides.clear();
+    for(std::set<FeaturePtr>::iterator
+        anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+      if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
+        aNewSetOfCoincides.insert(*anIt);
+      }
+    }
+    aCoincides = aNewSetOfCoincides;
+  }
+
+  return aCoincides;
+}
+
+std::set<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
+                                          const AttributePtr theAttribute) {
+  std::set<FeaturePtr> aFeaturesToBeRemoved;
+  std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
+  std::list<ResultPtr> aResults = theFeature->results();
+  for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
+      aResultsIt != aResults.cend();
+      ++aResultsIt) {
+    ResultPtr aResult = *aResultsIt;
+    std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
+    aRefs.insert(aResultRefs.begin(), aResultRefs.end());
+  }
+  for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
+    anIt != aRefs.cend();
+    ++anIt) {
+    std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+    if(aFeature->getKind() == SketchPlugin_Fillet::ID()) {
+      continue;
+    }
+    if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID()
+        || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()) {
+      aFeaturesToBeRemoved.insert(aFeature);
+    } else {
+      std::list<AttributePtr> anAttrs =
+          aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+      for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
+          aRefAttrsIt != anAttrs.cend();
+          ++aRefAttrsIt) {
+        AttributeRefAttrPtr anAttrRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
+        if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
+          aFeaturesToBeRemoved.insert(aFeature);
+        }
+      }
+    }
+  }
+  return aFeaturesToBeRemoved;
+}
diff --git a/src/SketchPlugin/SketchPlugin_Fillet.h b/src/SketchPlugin/SketchPlugin_Fillet.h
new file mode 100644 (file)
index 0000000..b25e025
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_Fillet.h
+// Created: 19 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_Fillet_H_
+#define SketchPlugin_Fillet_H_
+
+#include "SketchPlugin.h"
+
+#include "SketchPlugin_SketchEntity.h"
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_XY;
+
+/// \class SketchPlugin_Fillet
+/// \ingroup Plugins
+/// \brief Feature for creation of a new arc filleting two objects which have
+/// coincident point.
+class SketchPlugin_Fillet: public SketchPlugin_SketchEntity, public GeomAPI_IPresentable
+{
+ public:
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_FEATURE_ID("SketchFillet");
+    return MY_FEATURE_ID;
+  }
+
+  /// Attribute name of fillet point.
+  inline static const std::string& FILLET_POINT_ID()
+  {
+    static const std::string ID("fillet_point");
+    return ID;
+  }
+
+  /// \return the kind of a feature.
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_Fillet::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Creates a new part document if needed.
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes.
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+  /// Reimplemented from SketchPlugin_Feature::move().
+  /// Do nothing.
+  SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {};
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_Fillet();
+
+private:
+    FeaturePtr myBaseFeatures[2];
+    std::string myFeatAttributes[4]; // attributes of features
+    bool myIsReversed;
+    bool myIsNotInversed[2]; // indicates which point the features share
+    bool myFilletCreated;
+    std::shared_ptr<GeomAPI_XY> myCenterXY;
+    std::shared_ptr<GeomAPI_XY> myTangentXY1;
+    std::shared_ptr<GeomAPI_XY> myTangentXY2;
+};
+
+#endif
index e422ef436d2efd08f35a2a72014fda0ddc901420..87ef7b27a0dbf1e1e7148928fde3c77ef57adf85 100644 (file)
@@ -13,7 +13,7 @@
 #include <SketchPlugin_ConstraintCollinear.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
 #include <SketchPlugin_ConstraintSplit.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
@@ -165,8 +165,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_ConstraintMiddle);
   } else if (theFeatureID == SketchPlugin_ConstraintMirror::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintMirror);
-  } else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) {
-    return FeaturePtr(new SketchPlugin_ConstraintFillet);
+  } else if (theFeatureID == SketchPlugin_Fillet::ID()) {
+    return FeaturePtr(new SketchPlugin_Fillet);
   } else if (theFeatureID == SketchPlugin_ConstraintSplit::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintSplit);
   } else if (theFeatureID == SketchPlugin_MultiTranslation::ID()) {
@@ -234,7 +234,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_ConstraintTangent::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintMiddle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintMirror::ID(), aHasSketchPlane);
-      aMsg->setState(SketchPlugin_ConstraintFillet::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_Fillet::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintSplit::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane);
index 641aaa0fda9f2c372b18bb69bed61367986ec743..d42c783606ae58dc8d45bc5f5255c60d55d4c5a0 100755 (executable)
@@ -10,7 +10,7 @@
 #include "SketchPlugin_Circle.h"
 #include "SketchPlugin_ConstraintCoincidence.h"
 #include "SketchPlugin_ConstraintDistance.h"
-#include "SketchPlugin_ConstraintFillet.h"
+#include "SketchPlugin_Fillet.h"
 #include "SketchPlugin_ConstraintRigid.h"
 #include "SketchPlugin_ConstraintTangent.h"
 #include "SketchPlugin_Line.h"
@@ -483,195 +483,159 @@ bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribut
                                                  const std::list<std::string>& theArguments,
                                                  Events_InfoMessage& theError) const
 {
-  std::shared_ptr<SketchPlugin_ConstraintFillet> aFilletFeature =
-    std::dynamic_pointer_cast<SketchPlugin_ConstraintFillet>(theAttribute->owner());
-  AttributeRefAttrListPtr aPointsRefList =
-    std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
-  if(aPointsRefList->size() == 0) {
-    theError = "Error: List of points is empty.";
+  AttributeRefAttrPtr aPointRefAttr =
+    std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+  if(!aPointRefAttr.get()) {
+    theError = "Error: Point not selected.";
     return false;
   }
 
-  std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures> aPointsFeaturesMap =
-    aFilletFeature->pointsFeaturesMap();
-  std::set<AttributePtr> aSetOfPointsOnResultEdges;
-  for(std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures>::iterator
-      aPointsIter = aPointsFeaturesMap.begin();
-      aPointsIter != aPointsFeaturesMap.end();
-      ++aPointsIter) {
-    const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second;
-    const std::list<FeaturePtr>& aResultEdges = aFeatures.resultEdges;
-    for(std::list<FeaturePtr>::const_iterator aResultIter = aResultEdges.cbegin();
-        aResultIter != aResultEdges.cend();
-        ++aResultIter) {
-      FeaturePtr aResultFeature = *aResultIter;
-      if(aResultFeature->getKind() == SketchPlugin_Line::ID()) {
-        aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID()));
-        aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID()));
-      } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) {
-        aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID()));
-        aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID()));
-      }
-    }
+  AttributePtr aPointAttribute = aPointRefAttr->attr();
+  if (!aPointAttribute.get()) {
+    theError = "Error: Bad point selected.";
+    return false;
   }
+  std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
 
-  std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
-  for(std::list<std::pair<ObjectPtr, AttributePtr>>::const_iterator
-      aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) {
-    ObjectPtr anObject = (*aPointsIt).first;
-    AttributePtr aPointAttribute = (*aPointsIt).second;
-    if (!aPointAttribute.get())
-        return false;
-    std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
-
-    // If we alredy have some result then:
-    // - if it is the same point all ok, just skip it
-    // - if it is point on the fillet result edge then it is not valid
-    if(!aPointsFeaturesMap.empty()) {
-      if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) {
-        continue;
-      }
-
-      // Check that selected point not on the one of the fillet result edge.
-      if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) {
-        return false;
-      }
-    }
-
-    // Obtain constraint coincidence for the fillet point.
-    const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
-    FeaturePtr aConstraintCoincidence;
-    for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
-        anIt != aRefsList.cend(); ++anIt) {
-      std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
-      FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
-      if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
-        AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
-        AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-          aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
-        if(anAttrRefA.get() && !anAttrRefA->isObject()) {
-          AttributePtr anAttrA = anAttrRefA->attr();
-          if(aPointAttribute == anAttrA) {
-            aConstraintCoincidence = aConstrFeature;
-            break;
-          }
+  // Obtain constraint coincidence for the fillet point.
+  const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
+  FeaturePtr aConstraintCoincidence;
+  for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
+      anIt != aRefsList.cend(); ++anIt) {
+    std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
+    FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+    if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+      AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
+      if(anAttrRefA.get() && !anAttrRefA->isObject()) {
+        AttributePtr anAttrA = anAttrRefA->attr();
+        if(aPointAttribute == anAttrA) {
+          aConstraintCoincidence = aConstrFeature;
+          break;
         }
-        if(anAttrRefB.get() && !anAttrRefB->isObject()) {
-          AttributePtr anAttrB = anAttrRefB->attr();
-          if(aPointAttribute == anAttrB) {
-            aConstraintCoincidence = aConstrFeature;
-            break;
-          }
+      }
+      if(anAttrRefB.get() && !anAttrRefB->isObject()) {
+        AttributePtr anAttrB = anAttrRefB->attr();
+        if(aPointAttribute == anAttrB) {
+          aConstraintCoincidence = aConstrFeature;
+          break;
         }
       }
     }
+  }
 
-    if(!aConstraintCoincidence.get()) {
-      theError = "Error: one of the selected point does not have coicidence.";
-      return false;
+  if(!aConstraintCoincidence.get()) {
+    theError = "Error: one of the selected point does not have coicidence.";
+    return false;
+  }
+
+  // Get coincides from constraint.
+  std::set<FeaturePtr> aCoinsides;
+  SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
+                                        SketchPlugin_ConstraintCoincidence::ENTITY_A(),
+                                        aCoinsides);
+  SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
+                                        SketchPlugin_ConstraintCoincidence::ENTITY_B(),
+                                        aCoinsides);
+
+  // Remove points from set of coincides.
+  std::set<FeaturePtr> aNewSetOfCoincides;
+  for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
+      anIt != aCoinsides.end(); ++anIt) {
+    std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
+      std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
+    if(aSketchEntity.get() && aSketchEntity->isCopy()) {
+      continue;
+    }
+    if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
+        (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
+          continue;
     }
+    if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
+      AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
+      std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
+      double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
+      if(aDistSelectedArcCenter < tolerance) {
+        continue;
+      }
+    }
+    aNewSetOfCoincides.insert(*anIt);
+  }
+  aCoinsides = aNewSetOfCoincides;
 
-    // Get coincides from constraint.
-    std::set<FeaturePtr> aCoinsides;
-    SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
-                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
-                                         aCoinsides);
-    SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
-                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
-                                         aCoinsides);
-
-    // Remove points from set of coincides.
-    std::set<FeaturePtr> aNewSetOfCoincides;
+  // If we still have more than two coincides remove auxilary entities from set of coincides.
+  if(aCoinsides.size() > 2) {
+    aNewSetOfCoincides.clear();
     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
         anIt != aCoinsides.end(); ++anIt) {
-      if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
-         (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
-           continue;
-      }
-      if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
-        AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
-        std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
-        double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
-        if(aDistSelectedArcCenter < tolerance) {
-          continue;
-        }
+      if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
+        aNewSetOfCoincides.insert(*anIt);
       }
-      aNewSetOfCoincides.insert(*anIt);
     }
     aCoinsides = aNewSetOfCoincides;
+  }
 
-    // If we still have more than two coincides remove auxilary entities from set of coincides.
-    if(aCoinsides.size() > 2) {
-      aNewSetOfCoincides.clear();
-      for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
-          anIt != aCoinsides.end(); ++anIt) {
-        if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
-          aNewSetOfCoincides.insert(*anIt);
-        }
-      }
-      aCoinsides = aNewSetOfCoincides;
-    }
+  if(aCoinsides.size() != 2) {
+    theError = "Error: One of the selected points does not have two suitable edges for fillet.";
+    return false;
+  }
 
-    if(aCoinsides.size() != 2) {
-      theError = "Error: One of the selected points does not have two suitable edges for fillet.";
-      return false;
-    }
+  // Check that selected edges don't have tangent constraint.
+  std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
+  FeaturePtr aFirstFeature = *anIt++;
+  FeaturePtr aSecondFeature = *anIt;
+  const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
+  if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
+    theError = "Error: Edges in selected point has tangent constraint.";
+    return false;
+  }
 
-    // Check that selected edges don't have tangent constraint.
-    std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
-    FeaturePtr aFirstFeature = *anIt++;
-    FeaturePtr aSecondFeature = *anIt;
-    const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
-    if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
+  std::list<ResultPtr> aFirstResults = aFirstFeature->results();
+  for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
+      aResIt != aFirstResults.end(); ++aResIt) {
+    ResultPtr aRes = *aResIt;
+    const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
+    if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
       theError = "Error: Edges in selected point has tangent constraint.";
       return false;
     }
+  }
 
-    std::list<ResultPtr> aFirstResults = aFirstFeature->results();
-    for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
-        aResIt != aFirstResults.end(); ++aResIt) {
-      ResultPtr aRes = *aResIt;
-      const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
-      if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
-        theError = "Error: Edges in selected point has tangent constraint.";
-        return false;
-      }
-    }
-
-    // Check that lines not collinear
-    if(aFirstFeature->getKind() == SketchPlugin_Line::ID() &&
-        aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
-      std::string aStartAttr = SketchPlugin_Line::START_ID();
-      std::string anEndAttr = SketchPlugin_Line::END_ID();
-      std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
-      aFirstStartPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aFirstFeature->attribute(aStartAttr))->pnt();
-      aFirstEndPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
-      aSecondStartPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aSecondFeature->attribute(aStartAttr))->pnt();
-      aSecondEndPnt =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-        aSecondFeature->attribute(anEndAttr))->pnt();
-      double aCheck1 =
-        fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
-        (aSecondStartPnt->y() - aFirstStartPnt->y()) -
-        (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
-      double aCheck2 =
-        fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
-        (aSecondEndPnt->y() - aFirstStartPnt->y()) -
-        (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
-      if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
-        return false;
-      }
+  // Check that lines not collinear
+  if(aFirstFeature->getKind() == SketchPlugin_Line::ID() &&
+      aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::string aStartAttr = SketchPlugin_Line::START_ID();
+    std::string anEndAttr = SketchPlugin_Line::END_ID();
+    std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
+    aFirstStartPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aFirstFeature->attribute(aStartAttr))->pnt();
+    aFirstEndPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
+    aSecondStartPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aSecondFeature->attribute(aStartAttr))->pnt();
+    aSecondEndPnt =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aSecondFeature->attribute(anEndAttr))->pnt();
+    double aCheck1 =
+      fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
+      (aSecondStartPnt->y() - aFirstStartPnt->y()) -
+      (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
+    double aCheck2 =
+      fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
+      (aSecondEndPnt->y() - aFirstStartPnt->y()) -
+      (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
+    if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
+      return false;
     }
   }
 
+
   return true;
 }
 
index de5c42990da657c4777fa3001c115b36bdef0d2c..f7d332f696ebfe9d5b65994a4e64ec465a8fc33a 100755 (executable)
   </context>
 
   <context>
-    <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
     <message>
       <source>Double is not initialized.</source>
       <translation>Set the fillet radius</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
     <message>
       <source>Double is not positive.</source>
       <translation>The fillet radius must be positive</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
     <message>
       <source>Integer is not initialized.</source>
       <translation>Set the integer fillet radius</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+    <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
     <message>
       <source>Integer is not positive.</source>
       <translation>The integer fillet radius must be positive</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:Model_FeatureValidator</name>
+    <name>SketchFillet:Model_FeatureValidator</name>
     <message>
       <source>Attribute "ConstraintEntityA" is not initialized.</source>
       <translation>Select one or several points for filet</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:Model_FeatureValidator</name>
+    <name>SketchFillet:Model_FeatureValidator</name>
     <message>
       <source>Attribute "ConstraintValue" is not initialized.</source>
       <translation>Set the fillet radius</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
       <source>Error: List of points is empty.</source>
       <translation>List of points is empty</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
       <source>Error: one of the selected point does not have coicidence.</source>
       <translation>One of the selected point does not have coicidence</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
       <source>Error: One of the selected points does not have two suitable edges for fillet.</source>
       <translation>One of the selected points does not have two suitable edges for fillet</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
       <source>Error: Edges in selected point has tangent constraint.</source>
       <translation>Edges in selected point has tangent constraint</translation>
     </message>
   </context>
   <context>
-    <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+    <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
     <message>
       <source>Error: Edges in selected point has tangent constraint.</source>
       <translation>Edges in selected point has tangent constraint</translation>
index 50c1a6552572dd967245afc168ef4ae7530ba4a4..bf5db26b3dca4746f3c114b2525d585db8e89195 100644 (file)
@@ -12,7 +12,7 @@
                 SketchConstraintParallel SketchConstraintPerpendicular
                 SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
                 SketchConstraintEqual SketchConstraintTangent
-                SketchConstraintFillet SketchConstraintSplit SketchTrim
+                SketchFillet SketchConstraintSplit SketchTrim
                 SketchConstraintCoincidence
                 SketchConstraintMirror SketchConstraintAngle
                 SketchMultiRotation SketchMultiTranslation
       </feature>
 
       <!--  SketchConstraintFillet  -->
-      <feature id="SketchConstraintFillet" title="Fillet" tooltip="Create constraint defining fillet between two objects" icon="icons/Sketch/fillet.png">
-        <!--<sketch_shape_selector id="ConstraintEntityA"
-            label="Point" tooltip="Select point for fillet (should be shared by two entities only)" shape_types="vertex">
+      <feature id="SketchFillet"
+               title="Fillet"
+               tooltip="Create constraint defining fillet between two objects"
+               icon="icons/Sketch/fillet.png">
+        <sketch_shape_selector id="fillet_point"
+                               label="Point"
+                               tooltip="Select point for fillet (should be shared by two entities only)"
+                               shape_types="vertex">
           <validator id="SketchPlugin_FilletVertexValidator"/>
-        </sketch_shape_selector>-->
-        <sketch_multi_selector id="ConstraintEntityA"
-            label="Points:"
-            tooltip="Select points for fillets"
-            type_choice="Vertices"
-            greed = "true"
-            clear_in_neutral_point="false">
-          <validator id="SketchPlugin_FilletVertexValidator"/>
-        </sketch_multi_selector>
-        <labelvalue label="Radius" tooltip="Fillet arc radius" id="ConstraintValue" accept_expressions="0" min="0" use_reset="false"
-                     enable_value="enable_by_preferences">
-          <validator id="GeomValidators_Positive"/>
-        </labelvalue>
-        <validator id="PartSet_FilletSelection"/>
+        </sketch_shape_selector>
+        <!--<validator id="PartSet_FilletSelection"/>-->
       </feature>
       <!--  SketchConstraintSplit  -->
       <feature id="SketchConstraintSplit" title="Split"