]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Fillet updated to create necessary constraints (tangent, coincidence etc) in data...
authorazv <azv@opencascade.com>
Thu, 26 Mar 2015 12:08:51 +0000 (15:08 +0300)
committerazv <azv@opencascade.com>
Fri, 27 Mar 2015 07:42:14 +0000 (10:42 +0300)
src/GeomAPI/GeomAPI_XY.cpp
src/GeomAPI/GeomAPI_XY.h
src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.cpp
src/SketchSolver/SketchSolver_ConstraintManager.cpp

index ebe52e065e53b893c0787b242e136e0389ebc8ba..5cfeff6badaa0dc444d4d6b16a17f2eb9f1f7a10 100644 (file)
@@ -37,7 +37,16 @@ void GeomAPI_XY::setY(const double theY)
 
 const std::shared_ptr<GeomAPI_XY> GeomAPI_XY::added(const std::shared_ptr<GeomAPI_XY>& theArg)
 {
-  std::shared_ptr<GeomAPI_XY> aResult(new GeomAPI_XY(MY_XY->X() + theArg->x(), MY_XY->Y() + theArg->y()));
+  std::shared_ptr<GeomAPI_XY> aResult(new GeomAPI_XY(
+      MY_XY->X() + theArg->x(), MY_XY->Y() + theArg->y()));
+  return aResult;
+}
+
+const std::shared_ptr<GeomAPI_XY> GeomAPI_XY::decreased(
+    const std::shared_ptr<GeomAPI_XY>& theArg)
+{
+  std::shared_ptr<GeomAPI_XY> aResult(new GeomAPI_XY(
+      MY_XY->X() - theArg->x(), MY_XY->Y() - theArg->y()));
   return aResult;
 }
 
index 3649db87d9166f8517658b3ff3dff86129b86978..0438b3c38332c015df9621d7d82dd14e8ae9e0ca 100644 (file)
@@ -33,6 +33,8 @@ class GEOMAPI_EXPORT GeomAPI_XY : public GeomAPI_Interface
 
   /// result is sum of coordinates of this and the given argument
   const std::shared_ptr<GeomAPI_XY> added(const std::shared_ptr<GeomAPI_XY>& theArg);
+  /// result is difference between coordinates of this and the given argument
+  const std::shared_ptr<GeomAPI_XY> decreased(const std::shared_ptr<GeomAPI_XY>& theArg);
   /// result is coordinates multiplied by the argument
   const std::shared_ptr<GeomAPI_XY> multiplied(const double theArg);
 
index 22bc2541a224c8f24f04ab4ae12f7a39a0483d2a..23d1858b66b1d247a9da7c2f18a034e74c92f5dd 100644 (file)
@@ -6,19 +6,34 @@
 
 #include "SketchPlugin_ConstraintFillet.h"
 
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Line.h>
 #include <SketchPlugin_Sketch.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintRadius.h>
 
 #include <SketcherPrs_Factory.h>
 
 #include <Config_PropManager.h>
+#include <Events_Loop.h>
+
+/// \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);
+
 
 SketchPlugin_ConstraintFillet::SketchPlugin_ConstraintFillet()
 {
@@ -38,6 +53,8 @@ void SketchPlugin_ConstraintFillet::execute()
 {
   std::shared_ptr<ModelAPI_Data> aData = data();
   // Check the base objects are initialized
+  double aFilletRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+      aData->attribute(SketchPlugin_Constraint::VALUE()))->value();
   AttributeRefAttrPtr aBaseA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
   AttributeRefAttrPtr aBaseB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
@@ -62,20 +79,186 @@ void SketchPlugin_ConstraintFillet::execute()
 
   // Create list of objects composing a fillet
   // copy aFeatureA
-  FeaturePtr aNewFeature = sketch()->addFeature(aFeatureA->getKind());
-  aFeatureA->data()->copyTo(aNewFeature->data());
-  aRefListOfFillet->append(aNewFeature);
+  FeaturePtr aNewFeatureA = sketch()->addFeature(aFeatureA->getKind());
+  aFeatureA->data()->copyTo(aNewFeatureA->data());
+  aNewFeatureA->execute();
+  aRefListOfFillet->append(aNewFeatureA);
   // copy aFeatureB
-  aNewFeature = sketch()->addFeature(aFeatureB->getKind());
-  aFeatureB->data()->copyTo(aNewFeature->data());
-  aRefListOfFillet->append(aNewFeature);
+  FeaturePtr aNewFeatureB = sketch()->addFeature(aFeatureB->getKind());
+  aFeatureB->data()->copyTo(aNewFeatureB->data());
+  aNewFeatureB->execute();
+  aRefListOfFillet->append(aNewFeatureB);
   // create filleting arc
-  aNewFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
-  aNewFeature->attribute(SketchPlugin_Arc::CENTER_ID())->setInitialized();
-  aNewFeature->attribute(SketchPlugin_Arc::START_ID())->setInitialized();
-  aNewFeature->attribute(SketchPlugin_Arc::END_ID())->setInitialized();
-  aRefListOfFillet->append(aNewFeature);
+  FeaturePtr aNewArc = sketch()->addFeature(SketchPlugin_Arc::ID());
+  aRefListOfFillet->append(aNewArc);
   aRefListOfFillet->setInitialized();
+
+  // 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);
+
+  // Calculate arc attributes
+  static const int aNbFeatures = 2;
+  FeaturePtr aFeature[aNbFeatures] = {aNewFeatureA, aNewFeatureB};
+  std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures]; // tangent directions of the features in coincident point
+  bool isStart[aNbFeatures]; // indicates which point the features share
+  std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2]; // first pair of points relate to first feature, second pair -  to second
+  std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features
+  for (int i = 0; i < aNbFeatures; i++) {
+    std::string aStartAttr, aEndAttr;
+    if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
+      aStartAttr = SketchPlugin_Line::START_ID();
+      aEndAttr = SketchPlugin_Line::END_ID();
+    } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
+      aStartAttr = SketchPlugin_Arc::START_ID();
+      aEndAttr = SketchPlugin_Arc::END_ID();
+    } else { // wrong argument
+      aRefListOfFillet->remove(aNewFeatureA);
+      aRefListOfFillet->remove(aNewFeatureB);
+      aRefListOfFillet->remove(aNewArc);
+      return;
+    }
+    aFeatAttributes[2*i] = aStartAttr;
+    aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature[i]->attribute(aStartAttr))->pnt();
+    aFeatAttributes[2*i+1] = aEndAttr;
+    aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature[i]->attribute(aEndAttr))->pnt();
+  }
+  for (int i = 0; i < aNbFeatures; i++) {
+    int j = aNbFeatures;
+    for (; j < 2 * aNbFeatures; j++)
+      if (aStartEndPnt[i]->distance(aStartEndPnt[j]) < 1.e-10) {
+        isStart[0] = i==0;
+        isStart[1] = j==aNbFeatures;
+        break;
+      }
+    if (j < 2 * aNbFeatures)
+      break;
+  }
+  // tangent directions of the features
+  for (int i = 0; i < aNbFeatures; i++) {
+    std::shared_ptr<GeomAPI_XY> aDir;
+    if (aFeature[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 (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
+      std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+          aFeature[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])
+        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;
+
+  std::shared_ptr<GeomAPI_Pnt2d> aSharedPoint = aStartEndPnt[isStart[0] ? 0 : 1];
+  std::shared_ptr<GeomAPI_Dir2d> aBisect(new GeomAPI_Dir2d(
+      aTangentDir[0]->xy()->added(aTangentDir[1]->xy())));
+  std::shared_ptr<GeomAPI_XY> aStep = aBisect->xy()->multiplied(aFilletRadius);
+  std::shared_ptr<GeomAPI_XY> aCenter = aSharedPoint->xy()->added(aStep);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(
+      aCenter->x(), aCenter->y());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::START_ID()))->setValue(
+      aCenter->x() - aStep->y(), aCenter->y() + aStep->x());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(
+      aCenter->x() + aStep->y(), aCenter->y() - aStep->x());
+  aNewArc->execute();
+
+  // Create list of additional constraints:
+  // 1. Coincidence of boundary points of features 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(aNewArc->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(aFeature[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
+  recalculateAttributes(aNewArc, SketchPlugin_Arc::START_ID(), aFeature[aFeatInd], aFeatAttributes[anAttrInd]);
+  aConstraint->execute();
+  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(aNewArc->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(aFeature[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
+  recalculateAttributes(aNewArc, SketchPlugin_Arc::END_ID(), aFeature[aFeatInd], aFeatAttributes[anAttrInd]);
+  aConstraint->execute();
+  ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+  // recalculate center of fillet arc
+  std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+  aCenter = aStartPoint->xy()->added(aEndPoint->xy())->multiplied(0.5);
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(
+      aCenter->x(), aCenter->y());
+  // 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();
+  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(aNewArc->lastResult());
+    aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+    bool isArc = aFeature[i]->getKind() == SketchPlugin_Arc::ID();
+    aRefAttr->setObject(isArc ? aFeature[i]->lastResult() : aFeature[i]->firstResult());
+    aConstraint->execute();
+    ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+  }
+
+  // send events
+  ModelAPI_EventCreator::get()->sendUpdated(FeaturePtr(this), anUpdateEvent);
+  if (isUpdateFlushed)
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+  Events_Loop::loop()->flush(anUpdateEvent);
+
+  // make base features auxiliary
+  static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  aFeatureA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+  aFeatureB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+  ModelAPI_EventCreator::get()->sendUpdated(aFeatureA, aRedisplayEvent);
+  ModelAPI_EventCreator::get()->sendUpdated(aFeatureB, aRedisplayEvent);
+  Events_Loop::loop()->flush(aRedisplayEvent);
 }
 
 AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePrevious)
@@ -89,3 +272,41 @@ AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePreviou
 }
 
 
+
+// =========   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();
+  if (theFeature->getKind() == SketchPlugin_Line::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(
+        aEndPoint->xy()->decreased(aStartPoint->xy())));
+    std::shared_ptr<GeomAPI_XY> aVec = anArcPoint->xy()->decreased(aStartPoint->xy());
+    double aDot = aVec->dot(aLineDir->xy());
+    aVec = aStartPoint->xy()->added(aLineDir->xy()->multiplied(aDot));
+    anArcPoint->setX(aVec->x());
+    anArcPoint->setY(aVec->y());
+  } else if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
+    std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+    std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+    double aRadius = aStartPoint->distance(aCenterPoint);
+    std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(
+        anArcPoint->xy()->decreased(aCenterPoint->xy())));
+    std::shared_ptr<GeomAPI_XY> aPoint = aCenterPoint->xy()->added(aDir->xy()->multiplied(aRadius));
+    anArcPoint->setX(aPoint->x());
+    anArcPoint->setY(aPoint->y());
+  } else
+    return;
+
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theNewArc->attribute(theNewArcAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
+  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
+}
index 05171749b3acb6ac241f6e57aada2fa2994e468d..776be57bdb13a3605bd908e99eff3ba9f50746be 100644 (file)
@@ -894,6 +894,8 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
     if (!aFilletFeature)
       return false;
     aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature);
+    if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN)
+      return false; // not all attributes are initialized yet
     aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities);
   }
   // At first time, for correct result, move floating points of fillet on the middle points of base objects
@@ -934,34 +936,14 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
     }
   }
 
-  // Check the fillet arc which point to be connected to
-  bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively
-  Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1];
-  int aPos = Search(hEnt, myEntities);
-  Slvs_hParam anArcStartPoint = myEntities[aPos].param[0];
-  aPos = Search(anArcStartPoint, myParams);
-  double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
-  double aSqDistances[2];
-  int aPtInd;
-  for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-    aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt];
-    hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-    aPos = Search(hEnt, myEntities);
-    Slvs_hParam anObjectPoint = myEntities[aPos].param[0];
-    aPos = Search(anObjectPoint, myParams);
-    double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val};
-    aSqDistances[indEnt] = 
-        (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) +
-        (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]);
-  }
-  if (aSqDistances[1] < aSqDistances[0])
-    isArcInversed = true;
-
   // Create list of constraints to generate fillet
+  int aPtInd;
   std::vector<Slvs_hConstraint> aConstrList;
   bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists
   std::vector<Slvs_hConstraint>::iterator aCMapIter =
     isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin();
+  std::vector<Slvs_hConstraint>::iterator aCMapEnd =
+    isExists ? myConstraintMap[theConstraint].end() : aConstrList.end();
   int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0;
   for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
     // one point of fillet object should be coincident with the point on base, non-coincident with another base object
@@ -973,7 +955,7 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
       myConstraints[aCurConstrPos].ptB = aPtFillet;
       aCMapIter++;
       aCurConstrPos = Search(*aCMapIter, myConstraints);
-    } else {
+    } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
       Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
           ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
           0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
@@ -992,8 +974,9 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
         myConstraints[aCurConstrPos].ptA = aPtBase;
         myConstraints[aCurConstrPos].ptB = aPtFillet;
         aCMapIter++;
-        aCurConstrPos = Search(*aCMapIter, myConstraints);
-      } else {
+        if (aCMapIter != aCMapEnd)
+          aCurConstrPos = Search(*aCMapIter, myConstraints);
+      } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet
         aPonCurveConstr = Slvs_MakeConstraint(
             ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
             0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
@@ -1006,7 +989,8 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
       if (isExists) {
         myConstraints[aCurConstrPos].ptA = aPtFillet;
         aCMapIter++;
-        aCurConstrPos = Search(*aCMapIter, myConstraints);
+        if (aCMapIter != aCMapEnd)
+          aCurConstrPos = Search(*aCMapIter, myConstraints);
       } else {
         aPonCurveConstr = Slvs_MakeConstraint(
             ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
@@ -1018,56 +1002,13 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
       myConstraints.push_back(aPonCurveConstr);
       aConstrList.push_back(aPonCurveConstr.h);
     }
-
-    // Bound point of fillet arc should be tangently coincident with a bound point of fillet object
-    aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt);
-    Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd];
-    if (isExists) {
-      myConstraints[aCurConstrPos].ptA = aPtArc;
-      myConstraints[aCurConstrPos].ptB = aPtFillet;
-      aCMapIter++;
-      aCurConstrPos = Search(*aCMapIter, myConstraints);
-      myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
-      myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt];
-      myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt);
-      aCMapIter++;
-      aCurConstrPos = Search(*aCMapIter, myConstraints);
-    } else {
-      Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h,
-          0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aCoincConstr);
-      aConstrList.push_back(aCoincConstr.h);
-      Slvs_Constraint aTangency = Slvs_MakeConstraint(
-          ++myConstrMaxID, myID, aTangentType, myWorkplane.h,
-          0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]);
-      aTangency.other = (isArcInversed ? 1-indEnt : indEnt);
-      aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0;
-      myConstraints.push_back(aTangency);
-      aConstrList.push_back(aTangency.h);
-    }
   }
 
-  // Additional constraint for fillet diameter
-  double aRadius = 0.0;  // scalar value of the constraint
-  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      aConstrData->attribute(SketchPlugin_Constraint::VALUE()));
-  aRadius = aDistAttr->value();
-  if (isExists) {
-    myConstraints[aCurConstrPos].entityA = aFilletEnt[2];
-    myConstraints[aCurConstrPos].valA = aRadius * 2.0;
-    aCMapIter++;
-  } else {
-    Slvs_Constraint aDiamConstr = Slvs_MakeConstraint(
-        ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0,
-        SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN);
-    myConstraints.push_back(aDiamConstr);
-    aConstrList.push_back(aDiamConstr.h);
-
+  if (!isExists)
     myConstraintMap[theConstraint] = aConstrList;
-  }
 
   // Additional temporary constraints for base objects to be fixed
+  int aNbArcs = 0;
   for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
     if (!aBaseFeature[indAttr]) {
       AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
@@ -1075,17 +1016,24 @@ bool SketchSolver_ConstraintGroup::changeFilletConstraint(
       addTemporaryConstraintWhereDragged(aConstrAttr->attr());
       continue;
     }
-    std::list<AttributePtr> anAttributes =
-        aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::typeId());
-    std::list<AttributePtr>::iterator anIt = anAttributes.begin();
-    for ( ; anIt != anAttributes.end(); anIt++) {
-      // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message)
-      if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() &&
-          (*anIt)->id() == SketchPlugin_Arc::END_ID())
-        continue;
-      addTemporaryConstraintWhereDragged(*anIt);
+    if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) {
+      addTemporaryConstraintWhereDragged(
+          aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID()));
+      addTemporaryConstraintWhereDragged(
+          aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID()));
+    } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) {
+      // Arc should be fixed by its center only (to avoid "conflicting constraints" message)
+      // If the fillet is made on two arc, the shared point should be fixed too
+      aNbArcs++;
+      addTemporaryConstraintWhereDragged(
+          aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID()));
     }
   }
+  if (aNbArcs == 2) {
+      addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ?
+          aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) : 
+          aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID()));
+  }
   return true;
 }
 
index 72cb9f214437e8f224999e6390f26d32cc458f6d..1fafcf506b8e03cc5c2f5068d7e7f9febda211d1 100644 (file)
@@ -17,6 +17,7 @@
 #include <ModelAPI_Attribute.h>
 
 #include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
@@ -104,10 +105,19 @@ void SketchSolver_ConstraintManager::processEvent(
         }
       }
       // then get anything but not the sketch
+      // at first, add coincidence constraints, because they may be used by other constraints
       for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
         std::shared_ptr<SketchPlugin_Feature> aFeature = 
           std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
-        if (!aFeature)
+        if (!aFeature || aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
+          continue;
+        changeConstraintOrEntity(aFeature);
+      }
+      // after that, add all features except coincidence
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+        std::shared_ptr<SketchPlugin_Feature> aFeature = 
+          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+        if (!aFeature || aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
           continue;
         changeConstraintOrEntity(aFeature);
       }