]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
authorvsv <vitaly.smetannikov@opencascade.com>
Fri, 27 Mar 2015 14:14:15 +0000 (17:14 +0300)
committervsv <vitaly.smetannikov@opencascade.com>
Fri, 27 Mar 2015 14:14:15 +0000 (17:14 +0300)
26 files changed:
src/Config/Config_Common.cpp
src/Config/Config_Common.h
src/Config/Config_Keywords.h
src/Config/Config_ValidatorReader.cpp
src/Config/Config_ValidatorReader.h
src/GeomAPI/GeomAPI_XY.cpp
src/GeomAPI/GeomAPI_XY.h
src/GeomValidators/GeomValidators_Tools.cpp
src/Model/Model_AttributeReference.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/ModuleBase/ModuleBase_WidgetShapeSelector.cpp
src/ModuleBase/ModuleBase_WidgetValidated.cpp
src/PartSet/PartSet_Validators.cpp
src/PartSet/PartSet_Validators.h
src/PartSet/PartSet_WidgetShapeSelector.cpp
src/PartSet/PartSet_WidgetShapeSelector.h
src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp
src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp
src/SketchPlugin/SketchPlugin_ConstraintMirror.h
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/SketchSolver_ConstraintGroup.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.h
src/SketchSolver/SketchSolver_ConstraintManager.cpp

index 8ffc9e126b6938135b3cde07239281aae9969115..8c8cde4270d7a27265c77d29be1c0f0e68fbdaf0 100644 (file)
@@ -69,7 +69,7 @@ bool isWidgetNode(xmlNodePtr theNode)
 {\r
   if(!isElementNode(theNode))\r
     return false;\r
-  // it's parent is "feature" or "source"\r
+  // it's parent is "feature" or "source" or a page ("box", "case")\r
   if(!hasParent(theNode, NODE_FEATURE, NODE_SOURCE, \r
                          WDG_TOOLBOX_BOX, WDG_SWITCH_CASE, NULL))\r
     return false;\r
index 52fc1e1726fa0adbfedd95f72a7f3a930995c362..1850f8a7bd642373ed74ebdc4d262b443403410a 100644 (file)
@@ -43,6 +43,8 @@ CONFIG_EXPORT bool isElementNode(xmlNodePtr theNode);
  */
 CONFIG_EXPORT bool isNode(xmlNodePtr theNode, const char* theNodeName, ...);
 
+//#define isNode(p) _isNode(p, NULL)
+
 /*!
  * Checks if the given node is attribute node.
  * Attribute node represents a widget, that is able to store/restore
index afb80188ba9ec666a6163136b8c751095a2f8149..bc115a764f1ee1e1f5603126505031e3be70452f 100644 (file)
@@ -19,6 +19,7 @@ const static char* NODE_FEATURE = "feature";
 const static char* NODE_SOURCE = "source";
 const static char* NODE_VALIDATOR = "validator";
 const static char* NODE_SELFILTER = "selection_filter";
+const static char* NODE_XMLPARENT = "libxml_parent";
 
 // Widgets
 const static char* WDG_INFO = "label";
index d03dff58d7d6784c5bc572fd25639a5dad93c1bc..ef969cd55c06483042d92b18588ae955ac454025 100644 (file)
@@ -42,11 +42,26 @@ void Config_ValidatorReader::processNode(xmlNodePtr theNode)
     processSelectionFilter(theNode);
   } else if (isNode(theNode, NODE_FEATURE, NULL)) {
     storeAttribute(theNode, _ID);
+  } else if (isWidgetNode(theNode)) {
+    storeAttribute(theNode, _ID);
+    // Store widget name to restore it's id on validator/selector processing
+    myCurrentWidget = getNodeName(theNode);
   }
   //Process SOURCE nodes.
   Config_XMLReader::processNode(theNode);
 }
 
+void Config_ValidatorReader::cleanup(xmlNodePtr theNode)
+{
+  if (isNode(theNode, NODE_FEATURE, NULL)) {
+    cleanupAttribute(theNode, _ID);
+  } else if (isWidgetNode(theNode)) {
+    cleanupAttribute(NODE_XMLPARENT, _ID);
+    // Cleanup widget name when leave the widget node.
+    myCurrentWidget = "";
+  }
+}
+
 bool Config_ValidatorReader::processChildren(xmlNodePtr aNode)
 {
   return true;
@@ -63,14 +78,12 @@ void Config_ValidatorReader::processValidator(xmlNodePtr theNode)
   getParametersInfo(theNode, aValidatorId, aParameters);
   aMessage->setValidatorId(aValidatorId);
   aMessage->setValidatorParameters(aParameters);
-  //TODO(sbh): update feature/attribute id restoring
-  // when "cleanup" technique will be available (v. >= 1.1.0)
-  xmlNodePtr aFeatureOrWdgNode = theNode->parent;
-  if (isNode(aFeatureOrWdgNode, NODE_FEATURE, NULL)) {
-    aMessage->setFeatureId(getProperty(aFeatureOrWdgNode, _ID));
-  } else {
-    aMessage->setAttributeId(getProperty(aFeatureOrWdgNode, _ID));
-    aMessage->setFeatureId(restoreAttribute(NODE_FEATURE, _ID));
+  std::string aFeatureId = restoreAttribute(NODE_FEATURE, _ID);
+  aMessage->setFeatureId(aFeatureId);
+  // parent is attribute (widget)
+  if (!myCurrentWidget.empty()) {
+    std::string aParentId = restoreAttribute(myCurrentWidget.c_str(), _ID);
+    aMessage->setAttributeId(aParentId);
   }
   aEvLoop->send(aMessage);
 }
@@ -86,13 +99,12 @@ void Config_ValidatorReader::processSelectionFilter(xmlNodePtr theNode)
   getParametersInfo(theNode, aSelectionFilterId, aParameters);
   aMessage->setSelectionFilterId(aSelectionFilterId);
   aMessage->setFilterParameters(aParameters);
-
-  xmlNodePtr aFeatureOrWdgNode = theNode->parent;
-  if (isNode(aFeatureOrWdgNode, NODE_FEATURE, NULL)) {
-    aMessage->setFeatureId(getProperty(aFeatureOrWdgNode, _ID));
-  } else {
-    aMessage->setAttributeId(getProperty(aFeatureOrWdgNode, _ID));
-    aMessage->setFeatureId(restoreAttribute(NODE_FEATURE, _ID));
+  std::string aFeatureId = restoreAttribute(NODE_FEATURE, _ID);
+  aMessage->setFeatureId(aFeatureId);
+  // parent is attribute (widget)
+  if (!myCurrentWidget.empty()) {
+    std::string aParentId = restoreAttribute(myCurrentWidget.c_str(), _ID);
+    aMessage->setAttributeId(aParentId);
   }
   aEvLoop->send(aMessage);
 }
index f2ac6293d20adbe1fe86fd23c3a84554d525231f..59f6acffb0fc9d63dc6ed0bc672166c3d22b96f5 100644 (file)
@@ -45,6 +45,11 @@ class Config_ValidatorReader : public Config_XMLReader
    */
   virtual bool processChildren(xmlNodePtr aNode);
 
+  /*!
+   * Cleans the cached information about parent feature or attribute (widget)
+   */
+  virtual void cleanup(xmlNodePtr theNode);
+
   /*!
    * \brief Retrieves all the necessary info from the validator node.
    * Sends ValidatorLoaded event
@@ -55,6 +60,9 @@ class Config_ValidatorReader : public Config_XMLReader
    * Sends SelectionFilterLoaded event
    */
   void processSelectionFilter(xmlNodePtr theNode);
+
+ private:
+  std::string myCurrentWidget;
 };
 
 #endif /* CONFIG_VALIDATORREADER_H_ */
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 898296961797985cb3289a1a3bb066020a559a0b..9a78b5016b657e7ba80ff19dd66cab3f53c15b23 100644 (file)
@@ -23,12 +23,12 @@ namespace GeomValidators_Tools {
     }
     if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
       AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
-      if (anAttr != NULL && anAttr->isInitialized())
+      if (anAttr != NULL)
         anObject = anAttr->context();
     }
     if (anAttrType == ModelAPI_AttributeReference::typeId()) {
       AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
-      if (anAttr.get() != NULL && anAttr->isInitialized())
+      if (anAttr.get() != NULL)
         anObject = anAttr->value();
     }
     return anObject;
index 91de64eb567de9f94889a6274c98f8ae8c6dcebc..860968cdd14f40f5381cea5a5193c354163104e3 100644 (file)
@@ -45,7 +45,7 @@ void Model_AttributeReference::setValue(ObjectPtr theObject)
     // and reference from composite feature is removed automatically
     FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
     if (anOwnerFeature.get()) {
-      aData->addBackReference(anOwnerFeature, id());
+      aData->addBackReference(anOwnerFeature, id(), false);
     }
 
     owner()->data()->sendAttributeUpdated(this);
index f31bba3f33005d37a9486aca9a6f79a4e179a96c..ca0653fcc2ac05c0be6e13f45d6c37a2d525b372 100644 (file)
@@ -137,7 +137,7 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
 {
   std::shared_ptr<GeomAPI_Shape> aResult;
-  if (myIsInitialized) {
+  if (myRef.isInitialized()) {
     TDF_Label aSelLab = selectionLabel();
     if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
       ResultPtr aContext = context();
index d537db894aa04f9a905c4a8339b9c7ddfbaa555f..b3baaea43867efe74c0fa09eef6c3a1e6f1b1b7f 100644 (file)
@@ -259,10 +259,12 @@ void Model_Data::eraseBackReferences()
     aRes->setIsConcealed(false);
 }
 
-void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID)
+void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID, 
+   const bool theApplyConcealment)
 {
   myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
-  if (ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
+  if (theApplyConcealment && 
+      ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
     std::shared_ptr<ModelAPI_Result> aRes = 
       std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
     if (aRes) {
index 5a2f6296e1a385745534e42fd2c56312aa4be27a..8a45cfe64bc5d8fecd62fb73db28049c2a9bde64 100644 (file)
@@ -180,10 +180,14 @@ class Model_Data : public ModelAPI_Data
   MODEL_EXPORT virtual void copyTo(std::shared_ptr<ModelAPI_Data> theTarget);
 
 private:
-  /// removes all information about back references
+  /// Removes all information about back references
   void eraseBackReferences();
-  // adds a back reference (with identifier which attribute references to this object
-  void addBackReference(FeaturePtr theFeature, std::string theAttrID);
+  /// Adds a back reference (with identifier which attribute references to this object
+  /// \param theFeature feature referenced to this
+  /// \param theAttrID identifier of the attribute that is references from theFeature to this
+  /// \param theApplyConcealment applies consealment flag changes
+  void addBackReference(FeaturePtr theFeature, std::string theAttrID, 
+    const bool theApplyConcealment = true);
 };
 
 #endif
index c0e4faacff2ee5aa7af6fc1c1af5024f157dd20d..ef46fa06220feb56ad5b131594aab1b1d19ae299 100644 (file)
@@ -423,15 +423,6 @@ bool ModuleBase_WidgetShapeSelector::setSelection(const Handle_SelectMgr_EntityO
     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aIt;
     for (aIt = aResList.cbegin(); aIt != aResList.cend(); ++aIt) {
       if ((*aIt) == aRes)
-// TODO(nds): v1.0.2 (master)
-//  // Check the acceptability of the object as attribute
-//  aValidator = aValidators.begin();
-//  std::list<std::list<std::string> >::iterator aArgs = anArguments.begin();
-//  for (; aValidator != aValidators.end(); aValidator++, aArgs++) {
-//    const ModelAPI_RefAttrValidator* aAttrValidator =
-//        dynamic_cast<const ModelAPI_RefAttrValidator*>(*aValidator);
-//    if (aAttrValidator) {
-//      if (!aAttrValidator->isValid(myFeature, *aArgs, theObj, theShape)) {
         return false;
     }
   }
index e7285ab159157d243e0aa4447e99250fd1bc43b6..8f410e56d50dee27bcdebaaf8e7da61101ab0033 100644 (file)
@@ -11,6 +11,8 @@
 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
 #include <SelectMgr_EntityOwner.hxx>
 
+#include <Events_Loop.h>
+
 #include <QWidget>
 
 ModuleBase_WidgetValidated::ModuleBase_WidgetValidated(QWidget* theParent,
@@ -45,6 +47,11 @@ bool ModuleBase_WidgetValidated::isValid(const Handle_SelectMgr_EntityOwner& the
   AttributePtr anAttribute = myFeature->attribute(attributeID());
 
   // stores the current values of the widget attribute
+  Events_Loop* aLoop = Events_Loop::loop();
+  // blocks the flush signals to avoid the temporary objects visualization in the viewer
+  // they should not be shown in order to do not lose highlight by erasing them
+  aLoop->activateFlushes(false);
+
   aData->blockSendAttributeUpdated(true);
   bool isAttributeBlocked = anAttribute->blockSetInitialized(true);
   storeAttributeValue();
@@ -59,6 +66,7 @@ bool ModuleBase_WidgetValidated::isValid(const Handle_SelectMgr_EntityOwner& the
   restoreAttributeValue(aValid);
   aData->blockSendAttributeUpdated(false);
   anAttribute->blockSetInitialized(isAttributeBlocked);
+  aLoop->activateFlushes(true);
 
   return aValid;
 }
index 38bf03582b9d0a1bd9299078d981e3ef1414b3e9..6d17784f78dbcfc44b31410e0f8fa386089a33f6 100644 (file)
@@ -119,127 +119,84 @@ bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute
 {
   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
 
-  // 1. check whether the object of the attribute is not among the feature attributes
-  // find the attribute's object
-  ObjectPtr anObject =  GeomValidators_Tools::getObject(theAttribute);
+  // the type of validated attributes should be equal, attributes with different types are not validated
+  // Check RefAttr attributes
+  std::string anAttrType = theAttribute->attributeType();
+  std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
 
-  // check whether the object is not among other feature attributes
-  if (anObject.get() != NULL) {
-    // Check RefAttr attributes
-    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs = aFeature->data()->attributes("");
-    //if (anAttrs.size() > 0) {
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anIt = anAttrs.begin();
-    for(; anIt != anAttrs.end(); anIt++) {
-      AttributePtr anAttr = *anIt;
-      // the function parameter attribute should be skipped
-      if (anAttr.get() == NULL || anAttr->id() == theAttribute->id())
-        continue;
-      ObjectPtr aCurObject =  GeomValidators_Tools::getObject(anAttr);
-      if (aCurObject  && aCurObject == anObject)
-        return false;
+  if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
+    AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+    bool isObject = anAttr->isObject();
+    ObjectPtr anObject = anAttr->object();
+    AttributePtr anAttributeAttr = anAttr->attr();
+
+    anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+    if (anAttrs.size() > 0) {
+      std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
+      for(; anAttr != anAttrs.end(); anAttr++) {
+      if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
+          std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
+                                      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
+          if (aRef->isObject() != isObject)
+            continue;
+          if (isObject) {
+            if (aRef->object() == anObject)
+              return false;
+          }
+          else { // the attribute reference
+            if (aRef->attr() == theAttribute)
+              return false;
+          }
+        }
+      }
+    }
+  }
+  else if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
+    AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+    ResultPtr aContext = anAttr->context();
+    GeomShapePtr aShape = anAttr->value();
+
+    // Check selection attributes
+    anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
+    if (anAttrs.size() > 0) {
+      std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
+      for(; anAttr != anAttrs.end(); anAttr++) {
+        if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
+          std::shared_ptr<ModelAPI_AttributeSelection> aRef =
+                                        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
+          // check the object is already presented
+          if (aRef->context() == aContext) {
+            bool aHasShape = aShape.get() != NULL;
+            if (!aHasShape || aRef->value()->isEqual(aShape))
+              return false;
+          }
+        }
+      }
     }
   }
-  else {
-    // 2. collect object referenced by theAttribute and ...
-    if (featureHasReferences(theAttribute)) {
-      // 3. check whether the attribute value is not among other feature attributes
-      std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs = 
-        aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+  else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
+    AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
+    ObjectPtr anObject = anAttr->value();
+    // Check selection attributes
+    anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
+    if (anAttrs.size() > 0) {
       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
       for(; anAttr != anAttrs.end(); anAttr++) {
-        if (*anAttr) {
-          std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = 
-            std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
+        if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
+          std::shared_ptr<ModelAPI_AttributeReference> aRef =
+            std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
           // check the object is already presented
-          if (!aRef->isObject() && aRef->attr() == theAttribute)
+          if (aRef->value() == anObject)
             return false;
         }
-// TODO(nds) v1.0.2 master
-//bool PartSet_DifferentObjectsValidator::isValid(const FeaturePtr& theFeature,
-//                                                const std::list<std::string>& theArguments,
-//                                                const ObjectPtr& theObject,
-//                                                const GeomShapePtr& theShape) const
-//{
-//  // Check RefAttr attributes
-//  std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
-//    theFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-//  if (anAttrs.size() > 0) {
-//    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
-//    for(; anAttr != anAttrs.end(); anAttr++) {
-//      if (*anAttr) {
-//        std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
-//          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
-//        // check the object is already presented
-//        if (aRef->isObject() && aRef->object() == theObject)
-//          return false;
-//      }
-//    }
-//  }
-//  // Check selection attributes
-//  anAttrs = theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
-//  if (anAttrs.size() > 0) {
-//    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
-//    for(; anAttr != anAttrs.end(); anAttr++) {
-//      if (*anAttr) {
-//        std::shared_ptr<ModelAPI_AttributeSelection> aRef =
-//          std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
-//        // check the object is already presented
-//        if (aRef->isInitialized() && aRef->context() == theObject) {
-//          if (theShape.get() != NULL) {
-//            if (aRef->value()->isEqual(theShape))
-//              return false;
-//          } else
-//            return false;
-//        }
-//      }
-//    }
-//  }
-//  // Check selection attributes
-//  anAttrs = theFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
-//  if (anAttrs.size() > 0) {
-//    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
-//    for(; anAttr != anAttrs.end(); anAttr++) {
-//      if (*anAttr) {
-//        std::shared_ptr<ModelAPI_AttributeReference> aRef =
-//          std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
-//        // check the object is already presented
-//        if (aRef->isInitialized() && aRef->value() == theObject)
-//          return false;
-// ======= end of todo
+        return true;
       }
-      return true;
     }
   }
-  return true;
+  return !featureHasReferences(theAttribute);
 }
 
 bool PartSet_DifferentObjectsValidator::featureHasReferences(const AttributePtr& theAttribute) const
-// TODO(nds) v1.0.2 master
-//bool PartSet_DifferentObjectsValidator::isValid(const FeaturePtr& theFeature,
-//                                                const std::list<std::string>& theArguments,
-//                                                const AttributePtr& theAttribute) const
-//{
-//  if (PartSet_DifferentObjectsValidator::isValid(theAttribute, theArguments)) {
-//    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
-//      theFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
-//    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
-//    for(; anAttr != anAttrs.end(); anAttr++) {
-//      if (*anAttr) {
-//        std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
-//          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
-//        // check the object is already presented
-//        if (!aRef->isObject() && aRef->attr() == theAttribute)
-//          return false;
-//      }
-//    }
-//    return true;
-//  }
-//  return false;
-//}
-//
-//bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
-//                                                const std::list<std::string>& theArguments) const
-// ======= end of todo
 {
   std::list<std::pair<std::string, std::list<ObjectPtr> > > allRefs;
   if (theAttribute->owner().get() && theAttribute->owner()->data().get())
@@ -252,7 +209,7 @@ bool PartSet_DifferentObjectsValidator::featureHasReferences(const AttributePtr&
       anAttrObjs = &(aRefIter->second);
   }
   if (!anAttrObjs || anAttrObjs->empty())
-    return true; // theAttribute does not references to anything
+    return false; // theAttribute does not references to anything
   // check with all others
   for(aRefIter = allRefs.begin(); aRefIter != allRefs.end(); aRefIter++) {
     if (theAttribute->id() == aRefIter->first)
@@ -262,11 +219,11 @@ bool PartSet_DifferentObjectsValidator::featureHasReferences(const AttributePtr&
       std::list<ObjectPtr>::iterator aReferencedByMe = anAttrObjs->begin();
       for(; aReferencedByMe != anAttrObjs->end(); aReferencedByMe++) {
         if (*aReferenced == *aReferencedByMe) // found same objects!
-          return false;
+          return true;
       }
     }
   }
-  return true;
+  return false;
 }
 
 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
index 45df48dfdab1102d74496d45a53ed8e81c0aff60..7a7f2333c04bc740469e930e2f939843579a854d 100644 (file)
@@ -72,22 +72,6 @@ class PartSet_RigidValidator : public ModuleBase_SelectionValidator
 class PartSet_DifferentObjectsValidator : public ModelAPI_AttributeValidator
 {
  public:
-// TODO(nds) v1.0.2 master
-//   /// Returns True if the feature is valid
-//   /// \param theFeature a feature to check
-//   /// \param theArguments a list of arguments (names of attributes to check)
-//   /// \param theObject a selected object
-//   /// \param theShape a selected sub-shape
-//  virtual bool isValid(const FeaturePtr& theFeature, const std::list<std::string>& theArguments,
-//                       const ObjectPtr& theObject, const GeomShapePtr& theShape) const;
-//
-//  //! Returns true if the attribute is good for the feature attribute
-//  //! \param theFeature a feature to check
-//  //! \param theArguments a list of arguments (names of attributes to check)
-//  //! \param theAttribute an attribute
-//  virtual bool isValid(const FeaturePtr& theFeature, const std::list<std::string>& theArguments,
-//                       const AttributePtr& theAttribute) const;
-  // ======= end of todo
   //! Returns true if the attribute is good for the feature attribute
   //! \param theAttribute an attribute
   //! \param theArguments a list of arguments (names of attributes to check)
@@ -95,11 +79,6 @@ class PartSet_DifferentObjectsValidator : public ModelAPI_AttributeValidator
                        const std::list<std::string>& theArguments) const;
 
 protected:
-  //! Casts the attribute to an attribute kind and obtains an object value if it is possible
-  //! \param theAttribute a source attribute to find object
-  //! \return an attribute object or NULL
-  ObjectPtr getObject(const AttributePtr& theAttribute) const;
-
   //! Checks whethe other feature attributes has a reference to the given attribute
   //! \param theAttribute a source attribute to find object
   //! \return a boolean value
index 98c25d47b1dc4eda49d7e3e2af954673bc2ad324..fdda90f35cfba242aab573574a7695c001917c08 100644 (file)
 #include <PartSet_Tools.h>
 #include <SketchPlugin_Feature.h>
 
-#include <ModuleBase_IWorkshop.h>
-#include <XGUI_ModuleConnector.h>
-#include <XGUI_Workshop.h>
-#include <XGUI_Displayer.h>
-
 bool PartSet_WidgetShapeSelector::setObject(ObjectPtr theSelectedObject, GeomShapePtr theShape)
 {
   ObjectPtr aSelectedObject = theSelectedObject;
@@ -76,30 +71,11 @@ bool PartSet_WidgetShapeSelector::setObject(ObjectPtr theSelectedObject, GeomSha
   return ModuleBase_WidgetShapeSelector::setObject(aSelectedObject, aShape);
 }
 
-//********************************************************************
-void PartSet_WidgetShapeSelector::storeAttributeValue()
-{
-  /// this is a temporary code, will be removed when master is merged to this branch
-  /*XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
-  XGUI_Workshop* aWorkshop = aConnector->workshop();
-  aWorkshop->displayer()->enableUpdateViewer(false);
-  */
-  ModuleBase_WidgetShapeSelector::storeAttributeValue();
-}
-
 //********************************************************************
 void PartSet_WidgetShapeSelector::restoreAttributeValue(const bool theValid)
 {
   ModuleBase_WidgetShapeSelector::restoreAttributeValue(theValid);
-  /// this is a temporary code, will be removed when master is merged to this branch
-  /// after merge, the external edge should be removed always, without flag checking
-  if (!theValid)
-    removeExternal();
-  /*
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
-  XGUI_Workshop* aWorkshop = aConnector->workshop();
-  aWorkshop->displayer()->enableUpdateViewer(false);//->erase(myExternalObject);
-  aWorkshop->displayer()->enableUpdateViewer(true);*/
+  removeExternal();
 }
 
 //********************************************************************
@@ -111,40 +87,6 @@ void PartSet_WidgetShapeSelector::createExternal(ObjectPtr theSelectedObject,
   if (aObj != myExternalObject) {
     removeExternal();
     myExternalObject = aObj;
-// TODO(nds) v1.0.2 master
-//  // Check the acceptability of the object and shape as validator attribute
-//  AttributePtr aPntAttr;
-//  DataPtr aData = myFeature->data();
-//  if (theShape.get() != NULL) {
-//    AttributePtr aAttr = aData->attribute(attributeID());
-//    AttributeRefAttrPtr aRefAttr =
-//      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
-//    if (aRefAttr) {
-//      TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
-//      aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theObj, aShape, mySketch);
-//    }
-//  }
-//  // Check the acceptability of the object as attribute
-//  aValidator = aValidators.begin();
-//  std::list<std::list<std::string> >::iterator aArgs = anArguments.begin();
-//  for (; aValidator != aValidators.end(); aValidator++, aArgs++) {
-//    const ModelAPI_RefAttrValidator* aAttrValidator =
-//        dynamic_cast<const ModelAPI_RefAttrValidator*>(*aValidator);
-//    if (aAttrValidator) {
-//      if (aPntAttr.get() != NULL)
-//      {
-//        if (!aAttrValidator->isValid(myFeature, *aArgs, aPntAttr)) {
-//          return false;
-//        }
-//      }
-//      else
-//      {
-//        if (!aAttrValidator->isValid(myFeature, *aArgs, theObj, theShape)) {
-//          return false;
-//        }
-//      }
-//    }
-// ======= end of todo
   }
 }
 
index b47c59ebf2395270e16e5e35ae005d2d87f6d4ac..1ad2f21974b2ca5590286efbfcf0a04aa1d6444b 100644 (file)
@@ -49,11 +49,6 @@ protected:
   /// \param theShape a selected shape, which is used in the selection attribute
   virtual bool setObject(ObjectPtr theSelectedObject, GeomShapePtr theShape);
 
-  /// Creates a backup of the current values of the attribute
-  /// It should be realized in the specific widget because of different
-  /// parameters of the current attribute
-  virtual void storeAttributeValue();
-
   /// Creates a backup of the current values of the attribute
   /// It should be realized in the specific widget because of different
   /// parameters of the current attribute
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 f0da5515fa7a63ee32484a78dcfb5d5f2437f3bd..fde907d815e9e9616819398e4e1263cd4b610fa1 100644 (file)
@@ -10,7 +10,9 @@
 #include <ModelAPI_Data.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
 
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Sketch.h>
@@ -28,33 +30,96 @@ void SketchPlugin_ConstraintMirror::initAttributes()
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
+  AttributeSelectionListPtr aSelection = 
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(data()->addAttribute(
+    SketchPlugin_ConstraintMirror::MIRROR_LIST_ID(), ModelAPI_AttributeSelectionList::typeId()));
+  aSelection->setSelectionType("EDGE");
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
 }
 
 void SketchPlugin_ConstraintMirror::execute()
 {
-  // Objects to be mirrored will be created here
+  AttributeSelectionListPtr aMirrorObjectRefs =
+      selectionList(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID());
+  if (!aMirrorObjectRefs->isInitialized())
+    return;
+
   std::shared_ptr<ModelAPI_Data> aData = data();
   AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
       aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
-  if (!aRefListOfShapes->isInitialized())
-    return ;
-
   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
       aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
-  // Check consistency of initial list and mirrored list
   std::list<ObjectPtr> anInitialList =  aRefListOfShapes->list();
   std::list<ObjectPtr> aMirroredList =  aRefListOfMirrored->list();
+  std::vector<bool> isUsed(anInitialList.size(), false);
+  // add new items to the list
+  for(int anInd = 0; anInd < aMirrorObjectRefs->size(); anInd++) {
+    std::shared_ptr<ModelAPI_AttributeSelection> aSelect = aMirrorObjectRefs->value(anInd);
+    std::list<ObjectPtr>::const_iterator anIt = anInitialList.begin();
+    std::vector<bool>::iterator aUsedIt = isUsed.begin();
+    for (; anIt != anInitialList.end(); anIt++, aUsedIt++)
+      if (*anIt == aSelect->context()) {
+        *aUsedIt = true;
+        break;
+      }
+    if (anIt == anInitialList.end())
+      aRefListOfShapes->append(aSelect->context());
+  }
+  // remove unused items
   std::list<ObjectPtr>::iterator anInitIter = anInitialList.begin();
   std::list<ObjectPtr>::iterator aMirrorIter = aMirroredList.begin();
+  std::vector<bool>::iterator aUsedIter = isUsed.begin();
+  for (; aUsedIter != isUsed.end(); aUsedIter++) {
+    if (!(*aUsedIter)) {
+      aRefListOfShapes->remove(*anInitIter);
+      if (aMirrorIter != aMirroredList.end()) {
+        aRefListOfMirrored->remove(*aMirrorIter);
+        // remove the corresponding feature from the sketch
+        ResultConstructionPtr aRC =
+            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirrorIter);
+        DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
+        FeaturePtr aFeature =  aDoc ? std::dynamic_pointer_cast<SketchPlugin_Feature>(
+              aDoc->feature(aRC)) : FeaturePtr();
+        if (aFeature)
+          aDoc->removeFeature(aFeature);
+      }
+    }
+    if (anInitIter != anInitialList.end())
+      anInitIter++;
+    if (aMirrorIter != aMirroredList.end())
+      aMirrorIter++;
+  }
+
+  // Check consistency of initial list and mirrored list
+  anInitialList =  aRefListOfShapes->list();
+  anInitIter = anInitialList.begin();
+  aMirrorIter = aMirroredList.begin();
   int indFirstWrong = 0; // index of element starts difference in the lists
   std::set<int> anInvalidInd; // list of indices of removed features
   std::shared_ptr<SketchPlugin_Feature> aFeatureIn, aFeatureOut;
   for ( ; anInitIter != anInitialList.end(); anInitIter++, indFirstWrong++) {
     // Add features and store indices of objects to remove
     aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
-    aFeatureOut = aMirrorIter != aMirroredList.end() ? 
-        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter) :
-        std::shared_ptr<SketchPlugin_Feature>();
+    ResultConstructionPtr aRCIn;
+    if (!aFeatureIn) {
+      aRCIn = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
+      if (aRCIn)
+        aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(
+            aRCIn->document()->feature(aRCIn));
+    }
+    if (aMirrorIter == aMirroredList.end())
+      aFeatureOut = std::shared_ptr<SketchPlugin_Feature>();
+    else {
+      aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter);
+      if (!aFeatureOut) {
+        ResultConstructionPtr aRC =
+            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
+        if (aRC)
+          aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(
+              aRC->document()->feature(aRC));
+      }
+    }
     if (!aFeatureIn) {
       if (aFeatureOut)
         break; // the lists are inconsistent
@@ -66,7 +131,20 @@ void SketchPlugin_ConstraintMirror::execute()
       // There is no mirrored object yet, create it
       FeaturePtr aNewFeature = sketch()->addFeature(aFeatureIn->getKind());
       aFeatureIn->data()->copyTo(aNewFeature->data());
-      aRefListOfMirrored->append(aNewFeature);
+      aNewFeature->execute();
+
+      std::shared_ptr<GeomAPI_Shape> aShapeIn = aRCIn->shape();
+      const std::list<ResultPtr>& aResults = aNewFeature->results();
+      std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+      for (; anIt != aResults.end(); anIt++) {
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIt);
+        if (!aRC) continue;
+        std::shared_ptr<GeomAPI_Shape> aShapeOut = aRC->shape();
+        if ((aShapeIn->isVertex() && aShapeOut->isVertex()) ||
+            (aShapeIn->isEdge() && aShapeOut->isEdge()) ||
+            (aShapeIn->isFace() && aShapeOut->isFace()))
+          aRefListOfMirrored->append(aRC);
+      }
       continue;
     }
     if (aFeatureIn->getKind() != aFeatureOut->getKind())
index 841f11abd37718358f0249307d0fd857ac7b3994..69a26ea8f0f51e0b00a36934d5d67e7b56185c57 100644 (file)
@@ -38,6 +38,13 @@ class SketchPlugin_ConstraintMirror : public SketchPlugin_ConstraintBase
     return MY_KIND;
   }
 
+  /// List of objects to be mirrored
+  inline static const std::string& MIRROR_LIST_ID()
+  {
+    static const std::string MY_MIRROR_LIST_ID("ConstraintMirrorList");
+    return MY_MIRROR_LIST_ID;
+  }
+
   /// \brief Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
index 7fb075307806cadad45cbbd38c6b1bbe83d8c297..358c82c1b4982e73bf8875c5e31b952798c55d16 100644 (file)
@@ -67,9 +67,6 @@ bool SketchPlugin_DistanceAttrValidator::isValid(
   }
   return false;
 }
-
-
-
 bool SketchPlugin_TangentAttrValidator::isValid(
   const AttributePtr& theAttribute, const std::list<std::string>& theArguments ) const
 {
@@ -139,4 +136,3 @@ bool SketchPlugin_TangentAttrValidator::isValid(
 }
 
 
-
index 391738b8c3145b36b7813a8fbb8b2afc41863889..7274cc18dab72adb9939c9da12a5904ad506d7d5 100644 (file)
@@ -5,7 +5,7 @@
     <group id="Basic">
       <feature
         id="Sketch"
-        nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence"
+        nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror"
         when_nested="accept abort"
         title="Sketch"
         tooltip="Create a new sketch"
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
           <validator id="GeomValidators_EdgeOrVertex"/>
         </sketch_shape_selector>
- <!--
- TODO(nds): v1.0.2, master  
-                           shape_types="edge vertex">
-                       <validator id="PartSet_DifferentObjects"/>
-      <validator id="SketchPlugin_DistanceAttr" parameters="ConstraintEntityA"/>
-      <selection_filter id="MultiFilter" parameters="line,vertex"/>
-    </sketch_shape_selector>
-               
-        <sketch-2dpoint_selector id="ConstraintFlyoutValuePnt" internal="1" obligatory="0"/>
- -->
-        
         <sketch-2dpoint_selector id="ConstraintFlyoutValuePnt"  default="computed" internal="1" obligatory="0"/>
         
         <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed" min="0">
             <validator id="PartSet_DifferentObjects"/>
             <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
         </sketch_constraint_shape_selector>
-        
-<!--  
-  TODO(nds): v1.0.2, master  
-               <sketch_constraint_shape_selector id="ConstraintEntityA" 
-                       label="First line" tooltip="Select a line" shape_types="edge">
-                       <selection_filter id="EdgeFilter" parameters="line"/>
-               </sketch_constraint_shape_selector>
-               
-               <sketch_constraint_shape_selector id="ConstraintEntityB" label="Last line" tooltip="Select a line" 
-                       shape_types="edge">
-                       <selection_filter id="EdgeFilter" parameters="line"/>
-                       <validator id="PartSet_DifferentObjects"/>
-               </sketch_constraint_shape_selector>
-               
-        <sketch-2dpoint_selector id="ConstraintFlyoutValuePnt" internal="1" obligatory="0"/>
--->
         <validator id="PartSet_ParallelValidator"/>
       </feature>
       
           <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
             <validator id="GeomValidators_Edge" parameters="line"/>
         </sketch_constraint_shape_selector>
-<!--  
-  TODO(nds): v1.0.2, master
-               <sketch_constraint_shape_selector id="ConstraintEntityA" 
-                       label="First line" tooltip="Select an line" 
-                       shape_types="edge">
-      <selection_filter id="EdgeFilter" parameters="line"/>
-    </sketch_constraint_shape_selector>
-               
-               <sketch_constraint_shape_selector id="ConstraintEntityB" 
-                       label="Last line" tooltip="Select an line" 
-                       shape_types="edge">
-                       <validator id="PartSet_DifferentObjects"/>
-      <selection_filter id="EdgeFilter" parameters="line"/>
-    </sketch_constraint_shape_selector>
--->
         <validator id="PartSet_PerpendicularValidator"/>
       </feature>
 
       <feature
         id="SketchConstraintMirror"
         title="Mirror"
-        tooltip="Create constraint mirroring group of objects"
-        internal="1" />
+        tooltip="Create constraint, mirroring group of objects">
+        <sketch_constraint_shape_selector id="ConstraintEntityA" 
+            label="Mirror line" tooltip="Select mirror line" shape_types="edge">
+            <validator id="GeomValidators_Edge" parameters="line"/>
+        </sketch_constraint_shape_selector>
+        <multi_selector id="ConstraintMirrorList" 
+            label="List of objects"
+            tooltip="Select list of mirroring objects"
+            type_choice="Edges">
+        </multi_selector>
+      </feature>
     </group>
     
     <group id="Edit">
index 05171749b3acb6ac241f6e57aada2fa2994e468d..9b0ae4325756fb0ae42fef3ff50a45b56a89aeb7 100644 (file)
@@ -507,7 +507,9 @@ bool SketchSolver_ConstraintGroup::changeRigidConstraint(
         std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
     std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
-    if (aPoint || aPoint2D) {
+    std::shared_ptr<SketchPlugin_Point> aSketchPoint = 
+        std::dynamic_pointer_cast<SketchPlugin_Point>(aFeature);
+    if (aPoint || aPoint2D || aSketchPoint) {
       // Create SolveSpace constraint structure
       Slvs_Constraint aConstraint = Slvs_MakeConstraint(
           ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
@@ -616,9 +618,11 @@ bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
   // Search this constraint in the current group to update it
   ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
   std::vector<Slvs_Constraint>::iterator aConstrIter;
+  bool isExists = false;
   if (aConstrMapIter != myConstraintMap.end()) {
     int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
     aConstrIter = myConstraints.begin() + aConstrPos;
+    isExists = true;
   }
 
   // Get constraint type and verify the constraint parameters are correct
@@ -648,128 +652,155 @@ bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
   aMirrorLineEnt = aConstrAttr->isObject() ?
       changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
 
-  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-    // Append symmetric constraint for each point of mirroring features
-    AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        aConstrData->attribute(aConstraintAttributes[1]));
-    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-        aConstrData->attribute(aConstraintAttributes[2]));
-    if (!aBaseRefList || !aMirroredRefList)
-      return false;
-
-    std::list<ObjectPtr> aBaseList = aBaseRefList->list();
-    std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
-    if (aBaseList.size() != aMirroredList.size())
-      return false;
+  // Append symmetric constraint for each point of mirroring features
+  AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+    aConstrData->attribute(aConstraintAttributes[1]));
+  AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+    aConstrData->attribute(aConstraintAttributes[2]));
+  if (!aBaseRefList || !aMirroredRefList)
+    return false;
 
-    myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
+  std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+  std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+  if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
+    return false;
 
-    FeaturePtr aBaseFeature, aMirrorFeature;
-    ResultConstructionPtr aRC;
-    std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
-    std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
-    for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
-      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
-      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
-      aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
+  std::vector<Slvs_hConstraint> aNewConstraints;
+  // Fill the list of already mirrored points
+  std::vector<Slvs_Constraint> anOldConstraints;
+  std::map<Slvs_hEntity, Slvs_hEntity> aMirroredPoints;
+  if (isExists) {
+    std::vector<Slvs_hConstraint>::const_iterator aCIter = aConstrMapIter->second.begin();
+    for (; aCIter != aConstrMapIter->second.end(); aCIter++) {
+      int anInd = Search(*aCIter, myConstraints);
+      if (myConstraints[anInd].type != aConstrType)
+        continue;
+      aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB;
+      anOldConstraints.push_back(myConstraints[anInd]);
+    }
+  }
 
-      if (!aBaseFeature || !aMirrorFeature || 
-          aBaseFeature->getKind() != aMirrorFeature->getKind())
-        return false;
-      Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
-      Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
-      // Make aMirrorEnt parameters to be symmetric with aBaseEnt
-      makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
-
-      if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
-        Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
-            myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
-        myConstraints.push_back(aConstraint);
-        myConstraintMap[theConstraint].push_back(aConstraint.h);
-      } else {
-        int aBasePos = Search(aBaseEnt, myEntities);
-        int aMirrorPos = Search(aMirrorEnt, myEntities);
-        if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
-          for (int ind = 0; ind < 2; ind++) {
-            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-                myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
-                aMirrorLineEnt, SLVS_E_UNKNOWN);
-            myConstraints.push_back(aConstraint);
-            myConstraintMap[theConstraint].push_back(aConstraint.h);
-          }
-        } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
-          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-              myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
-              aMirrorLineEnt, SLVS_E_UNKNOWN);
-          myConstraints.push_back(aConstraint);
-          myConstraintMap[theConstraint].push_back(aConstraint.h);
-          // Additional constraint for equal radii
-          Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
-              ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
-              SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
-          myConstraints.push_back(anEqRadConstr);
-          myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
-        } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
-          // Workaround to avoid problems in SolveSpace.
-          // The symmetry of two arcs will be done using symmetry of three points on these arcs:
-          // start point, end point, and any other point on the arc
-          Slvs_hEntity aBaseArcPoints[3] = {
-              myEntities[aBasePos].point[1],
-              myEntities[aBasePos].point[2],
-              SLVS_E_UNKNOWN};
-          Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
-              myEntities[aMirrorPos].point[2],
-              myEntities[aMirrorPos].point[1],
-              SLVS_E_UNKNOWN};
-          Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
-          Slvs_hEntity aBothMiddlePoints[2];
-          for (int i = 0; i < 2; i++) {
-            double x, y;
-            calculateMiddlePoint(aBothArcs[i], x, y);
-            std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
-            Slvs_hParam u = changeParameter(x, aParamIter);
-            Slvs_hParam v = changeParameter(y, aParamIter);
-            Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
-            myEntities.push_back(aPoint);
-            aBothMiddlePoints[i] = aPoint.h;
-            // additional constraint point-on-curve
-            Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
-                ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
-                aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
-            myConstraints.push_back(aPonCircConstr);
-            myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
-          }
+  FeaturePtr aBaseFeature, aMirrorFeature;
+  ResultConstructionPtr aRC;
+  std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
+  std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
+  for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
+    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+    aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
+    aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
+
+    if (!aBaseFeature || !aMirrorFeature || 
+        aBaseFeature->getKind() != aMirrorFeature->getKind())
+      return false;
+    Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
+    Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
+    // Make aMirrorEnt parameters to be symmetric with aBaseEnt
+    makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt);
+
+    if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
+      Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt,
+          aMirrorLineEnt, anOldConstraints, aMirroredPoints);
+      aNewConstraints.push_back(anID);
+    } else {
+      int aBasePos = Search(aBaseEnt, myEntities);
+      int aMirrorPos = Search(aMirrorEnt, myEntities);
+      if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
+        for (int ind = 0; ind < 2; ind++) {
+          Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind],
+              myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
+          aNewConstraints.push_back(anID);
+        }
+      } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+        Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0],
+            myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints);
+        aNewConstraints.push_back(anID);
+        // Additional constraint for equal radii
+        Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+            ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
+            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
+        myConstraints.push_back(anEqRadConstr);
+        myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
+      } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
+        // Workaround to avoid problems in SolveSpace.
+        // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+        // start point, end point, and any other point on the arc
+        Slvs_hEntity aBaseArcPoints[3] = {
+            myEntities[aBasePos].point[1],
+            myEntities[aBasePos].point[2],
+            SLVS_E_UNKNOWN};
+        Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
+            myEntities[aMirrorPos].point[2],
+            myEntities[aMirrorPos].point[1],
+            SLVS_E_UNKNOWN};
+        Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt};
+        Slvs_hEntity aBothMiddlePoints[2];
+        for (int i = 0; i < 2; i++) {
+          double x, y;
+          calculateMiddlePoint(aBothArcs[i], x, y);
+          std::vector<Slvs_Param>::iterator aParamIter = myParams.end();
+          Slvs_hParam u = changeParameter(x, aParamIter);
+          Slvs_hParam v = changeParameter(y, aParamIter);
+          Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v);
+          myEntities.push_back(aPoint);
+          aBothMiddlePoints[i] = aPoint.h;
+          // additional constraint point-on-curve
+          Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
+              ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0,
+              aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN);
+          myConstraints.push_back(aPonCircConstr);
+          myConstraintMap[theConstraint].push_back(aPonCircConstr.h);
+        }
 
-          aBaseArcPoints[2] = aBothMiddlePoints[0];
-          aMirrorArcPoints[2] = aBothMiddlePoints[1];
-          for (int ind = 0; ind < 3; ind++) {
-            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-                aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN);
-            myConstraints.push_back(aConstraint);
-            myConstraintMap[theConstraint].push_back(aConstraint.h);
-          }
+        aBaseArcPoints[2] = aBothMiddlePoints[0];
+        aMirrorArcPoints[2] = aBothMiddlePoints[1];
+        for (int ind = 0; ind < 3; ind++) {
+          Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind],
+              aMirrorLineEnt, anOldConstraints, aMirroredPoints);
+          aNewConstraints.push_back(anID);
         }
       }
     }
+  }
+
+  // Remove unused constraints
+  std::vector<Slvs_Constraint>::const_iterator anOldCIter = anOldConstraints.begin();
+  for (; anOldCIter != anOldConstraints.end(); anOldCIter++) {
+    int anInd = Search(anOldCIter->h, myConstraints);
+    myConstraints.erase(myConstraints.begin() + anInd);
+  }
+  myConstraintMap[theConstraint] = aNewConstraints;
 
+  if (!isExists) {
     // Set the mirror line unchanged during constraint recalculation
     int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
-    Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
-        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-        myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    myConstraints.push_back(aRigidStart);
-    myConstraintMap[theConstraint].push_back(aRigidStart.h);
-    Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
-        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
-        myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-    myConstraints.push_back(aRigidEnd);
-    myConstraintMap[theConstraint].push_back(aRigidEnd.h);
+    // firstly check the line is not fixed yet
+    bool isFixed[2] = {false, false};
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++)
+      if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) {
+        if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0])
+          isFixed[0] = true;
+        else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1])
+          isFixed[1] = true;
+      }
+    // add new rigid constraints
+    if (!isFixed[0]) {
+      Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
+          ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+          myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+      myConstraints.push_back(aRigidStart);
+      myConstraintMap[theConstraint].push_back(aRigidStart.h);
+    }
+    if (!isFixed[1]) {
+      Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
+          ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+          myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+      myConstraints.push_back(aRigidEnd);
+      myConstraintMap[theConstraint].push_back(aRigidEnd.h);
+    }
 
     // Add temporary constraints for initial objects to be unchanged
     for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) {
@@ -894,6 +925,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 +967,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 +986,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 +1005,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 +1020,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 +1033,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 +1047,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;
 }
 
@@ -2198,6 +2177,44 @@ void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
   }
 }
 
+// ============================================================================
+//  Function: changeMirrorPoints
+//  Class:    SketchSolver_ConstraintGroup
+//  Purpose:  creates/updates mirror constraint for two points
+// ============================================================================
+Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints(
+    const Slvs_hEntity& theBasePoint,
+    const Slvs_hEntity& theMirrorPoint,
+    const Slvs_hEntity& theMirrorLine,
+    std::vector<Slvs_Constraint>&  thePrevConstr,
+    std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror)
+{
+  std::map<Slvs_hEntity, Slvs_hEntity>::iterator aMapIter = thePrevMirror.find(theBasePoint);
+  if (aMapIter != thePrevMirror.end()) {
+    thePrevMirror.erase(aMapIter);
+    std::vector<Slvs_Constraint>::const_iterator anIter = thePrevConstr.begin();
+    for (; anIter != thePrevConstr.end(); anIter++)
+      if (anIter->ptA == theBasePoint) {
+        if (anIter->ptB != theMirrorPoint) {
+          int aConstrInd = Search(anIter->h, myConstraints);
+          myConstraints[aConstrInd].ptB = theMirrorPoint;
+          myConstraints[aConstrInd].entityA = theMirrorLine;
+        }
+        Slvs_hConstraint aResult = anIter->h;
+        thePrevConstr.erase(anIter);
+        return aResult;
+      }
+  }
+
+  // Newly created constraint
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+      ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0,
+      theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN);
+  myConstraints.push_back(aConstraint);
+  return aConstraint.h;
+}
+
+
 // ============================================================================
 //  Function: calculateMiddlePoint
 //  Class:    SketchSolver_ConstraintGroup
index e24d93a7d2bf0e6814e89de8e5cbebe7e24a4e28..73dc23d633c878c870d9fe8113f4d63c223af8f4 100644 (file)
@@ -237,6 +237,20 @@ protected:
                         const Slvs_hEntity& theMirror,
                         const Slvs_hEntity& theMirrorLine);
 
+  /** \brief Creates/updates mirror constraint for two points
+   *  \param[in]     theBasePoint   ID of initial point
+   *  \param[in]     theMirrorPoint ID of the mirroring point
+   *  \param[in]     theMirrorLine  ID of the mirror line
+   *  \param[in]     thePrevConstr  list of previous constraints (the items will be deleted from the list if they are updated)
+   *  \param[in,out] thePrevMirror  list of previously mirrored points (the items will be deleted from the list if they are updated)
+   *  \return ID of created/updated constraint
+   */
+  Slvs_hConstraint changeMirrorPoints(const Slvs_hEntity& theBasePoint,
+                                      const Slvs_hEntity& theMirrorPoint,
+                                      const Slvs_hEntity& theMirrorLine,
+                                      std::vector<Slvs_Constraint>&  thePrevConstr,
+                                      std::map<Slvs_hEntity, Slvs_hEntity>& thePrevMirror);
+
   /** \brief Calculates middle point on line or arc
    *  \param[in]  theEntity  identifier of line or arc
    *  \param[out] theX       X value of middle point
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);
       }