]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom.git into Dev_1.1.0
authorsbh <sergey.belash@opencascade.com>
Mon, 6 Apr 2015 17:56:37 +0000 (20:56 +0300)
committersbh <sergey.belash@opencascade.com>
Mon, 6 Apr 2015 17:56:37 +0000 (20:56 +0300)
Conflicts:
src/ModelAPI/CMakeLists.txt
src/ModuleBase/ModuleBase_WidgetFactory.cpp

95 files changed:
src/InitializationPlugin/InitializationPlugin_Plugin.cpp
src/Model/Model_AttributeRefAttr.cpp
src/Model/Model_AttributeRefList.cpp
src/Model/Model_AttributeReference.cpp
src/Model/Model_AttributeSelection.cpp
src/Model/Model_Data.h
src/Model/Model_Document.cpp
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_AttributeValidator.cpp [new file with mode: 0644]
src/ModelAPI/ModelAPI_AttributeValidator.h
src/ModuleBase/ModuleBase_Operation.cpp
src/ModuleBase/ModuleBase_WidgetFactory.cpp
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_MenuMgr.cpp [new file with mode: 0644]
src/PartSet/PartSet_MenuMgr.h [new file with mode: 0644]
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_WidgetEditor.cpp [new file with mode: 0644]
src/PartSet/PartSet_WidgetEditor.h [new file with mode: 0644]
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/SketchPlugin/SketchPlugin_Constraint.h
src/SketchPlugin/SketchPlugin_ConstraintCoincidence.cpp
src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp
src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp
src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp
src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchPlugin/SketchPlugin_Line.h
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver.h
src/SketchSolver/SketchSolver_Builder.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Builder.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_Constraint.h
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintCoincidence.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintDistance.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintDistance.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintEqual.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintEqual.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintFillet.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintFillet.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintGroup.cpp [deleted file]
src/SketchSolver/SketchSolver_ConstraintGroup.h [deleted file]
src/SketchSolver/SketchSolver_ConstraintLength.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintLength.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/SketchSolver/SketchSolver_ConstraintManager.h
src/SketchSolver/SketchSolver_ConstraintMirror.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintMirror.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintRigid.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintRigid.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintTangent.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_ConstraintTangent.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Error.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_FeatureStorage.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_FeatureStorage.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Group.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Group.h [new file with mode: 0644]
src/SketchSolver/SketchSolver_Solver.cpp
src/SketchSolver/SketchSolver_Solver.h
src/SketchSolver/SketchSolver_Storage.cpp [new file with mode: 0644]
src/SketchSolver/SketchSolver_Storage.h [new file with mode: 0644]
src/SketcherPrs/SketcherPrs_Coincident.cpp
src/SketcherPrs/SketcherPrs_Coincident.h
src/SketcherPrs/SketcherPrs_Equal.cpp
src/SketcherPrs/SketcherPrs_Equal.h
src/SketcherPrs/SketcherPrs_Factory.cpp
src/SketcherPrs/SketcherPrs_Factory.h
src/SketcherPrs/SketcherPrs_HVDirection.cpp
src/SketcherPrs/SketcherPrs_HVDirection.h
src/SketcherPrs/SketcherPrs_LengthDimension.cpp
src/SketcherPrs/SketcherPrs_LengthDimension.h
src/SketcherPrs/SketcherPrs_Parallel.cpp
src/SketcherPrs/SketcherPrs_Parallel.h
src/SketcherPrs/SketcherPrs_Perpendicular.cpp
src/SketcherPrs/SketcherPrs_Perpendicular.h
src/SketcherPrs/SketcherPrs_Radius.cpp
src/SketcherPrs/SketcherPrs_Radius.h
src/SketcherPrs/SketcherPrs_Rigid.cpp
src/SketcherPrs/SketcherPrs_Rigid.h
src/SketcherPrs/SketcherPrs_SymbolPrs.cpp
src/SketcherPrs/SketcherPrs_SymbolPrs.h
src/SketcherPrs/SketcherPrs_Tangent.cpp
src/SketcherPrs/SketcherPrs_Tangent.h
src/SketcherPrs/SketcherPrs_Tools.cpp
src/SketcherPrs/SketcherPrs_Tools.h
src/XGUI/XGUI_ActionsMgr.cpp
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Displayer.h
src/XGUI/XGUI_ModuleConnector.cpp
src/XGUI/XGUI_Workshop.cpp

index 8270656852020ed435d8f0856abc319edddf92f2..b2ced2b57b3ef5372fa45dbaf9ddcb9a3b316240 100644 (file)
@@ -32,6 +32,12 @@ void InitializationPlugin_Plugin::processEvent(const std::shared_ptr<Events_Mess
     std::shared_ptr<ModelAPI_DocumentCreatedMessage> aMessage = std::dynamic_pointer_cast<
         ModelAPI_DocumentCreatedMessage>(theMessage);
     DocumentPtr aDoc = aMessage->document();
+
+    /// Issue 431: for the current moment create planes only in the module document,
+    /// Later if it is needed we may create special initial planes in Parts (may be different)
+    if (aDoc != ModelAPI_Session::get()->moduleDocument())
+      return;
+
     std::list<FeaturePtr> aFeatures;
 
     // the viewer update should be blocked in order to avoid the features blinking before they are
index 2d900eb142221d089617a372e714d182ebf54aa2..38e989e047ca7f10928df123f79e44117b43d02a 100644 (file)
@@ -23,8 +23,10 @@ void Model_AttributeRefAttr::setAttr(std::shared_ptr<ModelAPI_Attribute> theAttr
   string anID = aData->id(theAttr);
   if (myIsInitialized && object() == theAttr->owner() && myID->Get().IsEqual(anID.c_str()))
     return;  // nothing is changed
+  REMOVE_BACK_REF(theAttr->owner());
   myRef->Set(aData->label().Father());
   myID->Set(aData->id(theAttr).c_str());
+  ADD_BACK_REF(theAttr->owner());
   owner()->data()->sendAttributeUpdated(this);
 }
 
@@ -43,16 +45,9 @@ void Model_AttributeRefAttr::setObject(ObjectPtr theObject)
 {
   // the back reference from the previous object to the attribute should be removed
   ObjectPtr anObject = object();
-  if (anObject.get() && anObject != theObject) {
-    FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-    if (anOwnerFeature.get()) {
-      std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
-                                          anObject->data());
-      aData->removeBackReference(anOwnerFeature, id());
-    }
-  }
-
   if (theObject && (!myIsInitialized || myID->Get().Length() != 0 || object() != theObject)) {
+    REMOVE_BACK_REF(anObject);
+
     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
         theObject->data());
     myRef->Set(aData->label().Father());
@@ -64,8 +59,10 @@ void Model_AttributeRefAttr::setObject(ObjectPtr theObject)
     if (anOwnerFeature.get()) {
       aData->addBackReference(anOwnerFeature, id(), false);
     }
+    ADD_BACK_REF(theObject);
     owner()->data()->sendAttributeUpdated(this);
   } else if (theObject.get() == NULL) {
+    REMOVE_BACK_REF(anObject);
     myRef->Set(myRef->Label()); // reference to itself means that object is null
     myID->Set("");  // feature is identified by the empty ID
     owner()->data()->sendAttributeUpdated(this);
index c9722835887b00258b8e1acbac9797dac0dd06c1..c09190f3326da11cd0057ac0236d4397780762c9 100644 (file)
@@ -18,10 +18,7 @@ void Model_AttributeRefList::append(ObjectPtr theObject)
   myRef->Append(aData->label().Father());  // store label of the object
   // do it before the transaction finish to make just created/removed objects know dependencies
   // and reference from composite feature is removed automatically
-  FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-  if (anOwnerFeature.get()) {
-    aData->addBackReference(anOwnerFeature, id());
-  }
+  ADD_BACK_REF(theObject);
 
   owner()->data()->sendAttributeUpdated(this);
 }
@@ -42,6 +39,7 @@ void Model_AttributeRefList::remove(ObjectPtr theObject)
         ObjectPtr anObj = aDoc->object(aLIter.Value());
         if (anObj.get() == NULL) {
           myRef->Remove(aLIter.Value());
+          REMOVE_BACK_REF(theObject);
           break;
         }
       }
index 860968cdd14f40f5381cea5a5193c354163104e3..9c51e545b66ee0983cfcb17eb8747ce7dfe96654 100644 (file)
@@ -21,9 +21,12 @@ void Model_AttributeReference::setValue(ObjectPtr theObject)
 {
   if(!theObject)
     return;
-  if (!myIsInitialized || value() != theObject) {
+  ObjectPtr aValue = value();
+  if (!myIsInitialized || aValue != theObject) {
+    REMOVE_BACK_REF(aValue);
+
     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(
-        theObject->data());
+      theObject->data());
     TDF_Label anObjLab = aData->label().Father(); // object label
 
     if (owner()->document() == theObject->document()) { // same document, use reference attribute
@@ -43,10 +46,7 @@ void Model_AttributeReference::setValue(ObjectPtr theObject)
     }
     // do it before the transaction finish to make just created/removed objects know dependencies
     // and reference from composite feature is removed automatically
-    FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-    if (anOwnerFeature.get()) {
-      aData->addBackReference(anOwnerFeature, id(), false);
-    }
+    ADD_BACK_REF(theObject);
 
     owner()->data()->sendAttributeUpdated(this);
   }
index ca0653fcc2ac05c0be6e13f45d6c37a2d525b372..3e23333451931c81706be68835312774179d2a04 100644 (file)
@@ -92,7 +92,7 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext,
   if (theSubShape.get() && !theSubShape->isNull() && theSubShape->isEdge()) {
     const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
     if (aSubShape.ShapeType() == TopAbs_EDGE)
-      isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape));
+      isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape)) == Standard_True;
   }
   if (!theContext.get() || isDegeneratedEdge) {
     // to keep the reference attribute label
index f3fd1c384e8dfa7c6704e0f3f9cf357e64bfa60a..93de6977de7bb6cd633575d623c99ecb60a3d36f 100644 (file)
@@ -195,4 +195,28 @@ private:
     const bool theApplyConcealment = true);
 };
 
+/// Generic method to register back reference, used in referencing attributes.
+/// Without concealment change, it will be done later, on synchronization.
+#define ADD_BACK_REF(TARGET) \
+  if (TARGET.get() != NULL) { \
+    FeaturePtr anAttributeOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
+    if (anAttributeOwnerFeature.get()) { \
+      std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
+        (TARGET)->data()); \
+      aTargetData->addBackReference(anAttributeOwnerFeature, id(), false); \
+    } \
+  }
+
+/// Generic method to unregister back reference, used in referencing attributes.
+/// Without concealment change, it will be done later, on synchronization.
+#define REMOVE_BACK_REF(TARGET) \
+  if (TARGET.get() != NULL) { \
+    FeaturePtr anAttOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner()); \
+    if (anAttOwnerFeature.get()) { \
+      std::shared_ptr<Model_Data> aTargetData = std::dynamic_pointer_cast<Model_Data>( \
+        (TARGET)->data()); \
+      aTargetData->removeBackReference(anAttOwnerFeature, id()); \
+    } \
+  }
+
 #endif
index 0f335a5302a94eddb266c46129e3470425fde401..71019bc6d50f4baa503565c0b455b7da4773e737 100644 (file)
@@ -404,8 +404,8 @@ void Model_Document::abortOperation()
       myDoc->Undo();
     myDoc->ClearRedos();
   }
-  // references were not changed since transaction start
-  synchronizeFeatures(true, false, isRoot());
+  // references may be changed because they are set in attributes on the fly
+  synchronizeFeatures(true, true, isRoot());
   // abort for all subs
   const std::set<std::string> aSubs = subDocuments(true);
   std::set<std::string>::iterator aSubIter = aSubs.begin();
index 513ddcdefca87d6d94a59b7b45cbd52c31ee0e2a..249ee64ac25822fe2cac6c51fbe3d0bb99f91797 100644 (file)
@@ -69,6 +69,7 @@ SET(PROJECT_SOURCES
     ModelAPI_ShapeValidator.cpp
     ModelAPI_Tools.cpp
     ModelAPI_ResultParameter.cpp
+    ModelAPI_AttributeValidator.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/ModelAPI/ModelAPI_AttributeValidator.cpp b/src/ModelAPI/ModelAPI_AttributeValidator.cpp
new file mode 100644 (file)
index 0000000..12c9de0
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        ModelAPI_AttributeValidator.cpp
+// Created:     4 Sep 2014
+// Author:      Mikhail PONIKAROV
+
+#include <ModelAPI_AttributeValidator.h>
+
+ModelAPI_AttributeValidator::~ModelAPI_AttributeValidator()
+{
+
+}
index f059b9c659d4571ff5f03ed0b061bdd81c1a87a4..151c793c21ee3445fdaf36b9eaf5873f6f3ebd3e 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef ModelAPI_AttributeValidator_H
 #define ModelAPI_AttributeValidator_H
 
+#include <ModelAPI.h>
 #include <ModelAPI_Attribute.h>
 #include <ModelAPI_Validator.h>
 
@@ -21,6 +22,8 @@ public:
   //! \param theArguments arguments of the attribute
   virtual bool isValid(const AttributePtr& theAttribute,
                        const std::list<std::string>& theArguments) const = 0;
+
+  MODELAPI_EXPORT ~ModelAPI_AttributeValidator();
 };
 
 #endif
index 084ba04bf563f555f4ad9d2bad5d631d6ba55f13..68dd1322176bd6a73e83687402f769d7f0e99946 100644 (file)
@@ -239,12 +239,12 @@ void ModuleBase_Operation::activateByPreselection()
     }
   }
   // 2. ignore not obligatory widgets
-  for (; aWIt != aWidgets.constEnd(); ++aWIt) {
+  /*for (; aWIt != aWidgets.constEnd(); ++aWIt) {
     aWgt = (*aWIt);
     if (aWgt && aWgt->isObligatory())
       continue;
     aFilledWgt = aWgt;
-  }
+  }*/
 
   // 3. activate the next obligatory widget
   myPropertyPanel->activateNextWidget(aFilledWgt);
index eedb3a390759f687d552ed6e15fcbe8a7d0e23aa..c9561a13ba458fddc63d95e139bcaa1c7bc18fb1 100644 (file)
@@ -126,8 +126,8 @@ ModuleBase_ModelWidget* ModuleBase_WidgetFactory::createWidgetByType(const std::
     result = new ModuleBase_WidgetShapeSelector(theParent, myWorkshop, myWidgetApi, myParentId);
   } else if (theType == WDG_BOOLVALUE) {
     result = new ModuleBase_WidgetBoolValue(theParent, myWidgetApi, myParentId);
-  } else if (theType == WDG_DOUBLEVALUE_EDITOR) {
-    result = new ModuleBase_WidgetEditor(theParent, myWidgetApi, myParentId);
+  //} else if (theType == WDG_DOUBLEVALUE_EDITOR) {
+  //  result = new ModuleBase_WidgetEditor(theParent, myWidgetApi, myParentId);
   } else if (theType == WDG_FILE_SELECTOR) {
     result = new ModuleBase_WidgetFileSelector(theParent, myWidgetApi, myParentId);
   } else if (theType == WDG_CHOICE) {
index d10a13c9f857fa9c5c978713521a59784a5e2d18..8b85b15c621600b877eeba50480d98dcdd6dc25c 100644 (file)
@@ -13,11 +13,13 @@ SET(PROJECT_HEADERS
        PartSet_Validators.h
        PartSet_WidgetPoint2d.h
        PartSet_WidgetConstraintShapeSelector.h
+    PartSet_WidgetEditor.h
        PartSet_WidgetPoint2dDistance.h
        PartSet_WidgetShapeSelector.h
        PartSet_Filters.h
        PartSet_FilterSketchEntity.h
        PartSet_SketcherMgr.h
+       PartSet_MenuMgr.h
 )
 
 SET(PROJECT_SOURCES
@@ -26,12 +28,14 @@ SET(PROJECT_SOURCES
        PartSet_WidgetSketchLabel.cpp
        PartSet_Validators.cpp
        PartSet_WidgetConstraintShapeSelector.cpp
+    PartSet_WidgetEditor.cpp
        PartSet_WidgetPoint2d.cpp
        PartSet_WidgetPoint2dDistance.cpp
        PartSet_WidgetShapeSelector.cpp
        PartSet_Filters.cpp
        PartSet_FilterSketchEntity.cpp
        PartSet_SketcherMgr.cpp
+       PartSet_MenuMgr.cpp
 )
 
 SET(PROJECT_RESOURCES 
diff --git a/src/PartSet/PartSet_MenuMgr.cpp b/src/PartSet/PartSet_MenuMgr.cpp
new file mode 100644 (file)
index 0000000..9b02aee
--- /dev/null
@@ -0,0 +1,387 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_MenuMgr.cpp
+// Created:     03 April 2015
+// Author:      Vitaly SMETANNIKOV
+
+#include "PartSet_MenuMgr.h"
+#include "PartSet_Module.h"
+#include "PartSet_SketcherMgr.h"
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Point.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_Operation.h>
+
+#include <XGUI_ModuleConnector.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <Events_Loop.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
+
+#include <QAction>
+#include <QMenu>
+
+PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
+  : QObject(theModule), myModule(theModule), myPrevId(-1)
+{
+  createActions();
+}
+
+
+QAction* PartSet_MenuMgr::action(const QString& theId) const
+{
+  if (myActions.contains(theId))
+    return myActions[theId];
+  return 0;
+}
+
+void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
+{
+  if (myActions.contains(theId))
+    qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
+  theAction->setData(theId);
+  connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
+  myActions[theId] = theAction;
+}
+
+void PartSet_MenuMgr::createActions()
+{
+  QAction* anAction;
+
+  anAction = new QAction(tr("Auxiliary"), this);
+  anAction->setCheckable(true);
+  addAction("AUXILIARY_CMD", anAction);
+}
+
+
+void PartSet_MenuMgr::onAction(bool isChecked)
+{
+  QAction* aAction = static_cast<QAction*>(sender());
+  QString anId = aAction->data().toString();
+
+  if (anId == "AUXILIARY_CMD") {
+    setAuxiliary(isChecked);
+  }
+}
+
+/// Returns point of coincidence feature
+/// \param theFeature the coincidence feature
+/// \param theAttribute the attribute name
+std::shared_ptr<GeomAPI_Pnt2d> getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                        const std::string& theAttribute)
+{
+  std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
+
+  if (!theFeature->data())
+    return std::shared_ptr<GeomAPI_Pnt2d>();
+
+  FeaturePtr aFeature;
+  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
+      ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
+  if (anAttr)
+    aFeature = ModelAPI_Feature::feature(anAttr->object());
+
+  if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
+    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
+
+  else if (aFeature &&  aFeature->getKind() == SketchPlugin_Circle::ID())
+    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
+
+  else if (anAttr->attr()) {
+    aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+  }
+  if (aPointAttr.get() != NULL)
+    return aPointAttr->pnt();
+  return std::shared_ptr<GeomAPI_Pnt2d>();
+}
+
+/// Returns list of features connected in a councedence feature point
+/// \param theStartCoin the coincidence feature
+/// \param theList a list which collects lines features
+/// \param theAttr the attribute name
+void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
+{
+  AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
+  FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
+  if (!theList.contains(aObj)) {
+    std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
+    theList.append(aObj);
+    const std::set<AttributePtr> aRefsList = aObj->data()->refsToMe();
+    std::set<AttributePtr>::const_iterator aIt;
+    for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
+      std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+      FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+      if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { 
+        std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
+        if (aOrig->isEqual(aPnt)) {
+          findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+          findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+        }
+      }
+    }
+  }
+}
+
+
+bool PartSet_MenuMgr::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
+{
+  ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+  if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
+      !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+    return false;
+
+  myCoinsideLines.clear();
+  ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+  QObjectPtrList aObjects = aSelection->selectedPresentations();
+  if (aObjects.size() > 0) {
+    bool hasFeature = false;
+    FeaturePtr aFeature;
+    foreach(ObjectPtr aObject, aObjects) {
+      aFeature = ModelAPI_Feature::feature(aObject);
+      if (aFeature.get() != NULL) {
+        hasFeature = true;
+      }
+    }
+    if (hasFeature) {
+      bool aIsDetach = false;
+      if (aObjects.size() == 1) {
+        if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+          /// If the feature is coincident then we use Detach command instead Delete
+          mySelectedFeature = aFeature;
+          findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+          findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+          if (myCoinsideLines.size() > 0) {
+            aIsDetach = true;
+            QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
+            QAction* aAction;
+            int i = 0;
+            foreach (FeaturePtr aCoins, myCoinsideLines) {
+              aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
+              aAction->setData(QVariant(i));
+              i++;
+            }
+            connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
+            connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
+            connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
+          } 
+        }
+      } 
+      if (!aIsDetach)
+        theMenu->addAction(theStdActions["DELETE_CMD"]);
+    }
+  }
+  bool isAuxiliary;
+  if (canSetAuxiliary(isAuxiliary)) {
+    QAction* anAction = action("AUXILIARY_CMD");
+    theMenu->addAction(anAction);
+    anAction->setChecked(isAuxiliary);
+  }
+  return true;
+}
+
+void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
+{
+  if (myPrevId != -1) {
+    // Restore color for previous object
+    setLineColor(myPrevId, myColor, false);
+  }
+  myPrevId = theAction->data().toInt();
+  myColor = setLineColor(myPrevId, Qt::white, true);
+}
+
+QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
+{
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+  XGUI_Workshop* aWorkshop = aConnector->workshop();
+  XGUI_Displayer* aDisplayer = aWorkshop->displayer();
+
+  FeaturePtr aLine = myCoinsideLines.at(myPrevId);
+  std::list<ResultPtr>::const_iterator aIt;
+  const std::list<ResultPtr>& aResults = aLine->results();
+  QColor aColor;
+  for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
+    aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
+  }
+  if (theUpdate)
+    aDisplayer->updateViewer();
+  return aColor;
+}
+
+
+void PartSet_MenuMgr::onLineDetach(QAction* theAction)
+{
+  int aId = theAction->data().toInt();
+  FeaturePtr aLine = myCoinsideLines.at(aId);
+  std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+  gp_Pnt aOr = aOrig->impl<gp_Pnt>();
+  const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
+
+  QObjectPtrList aToDelFeatures;
+  std::set<AttributePtr>::const_iterator aIt;
+  // Find all coincedences corresponded to the selected line in the selected point
+  for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
+    std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
+    FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+    if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { 
+      std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
+      gp_Pnt aP = aPnt->impl<gp_Pnt>();
+      if (aOrig->isEqual(aPnt)) {
+        aToDelFeatures.append(aConstrFeature);
+      } else {
+        aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
+        aP = aPnt->impl<gp_Pnt>();
+        if (aOrig->isEqual(aPnt)) {
+          aToDelFeatures.append(aConstrFeature);
+          break;
+        }
+      }
+    }
+  }
+  if (aToDelFeatures.size() > 0) {
+    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
+    XGUI_Workshop* aWorkshop = aConnector->workshop();
+    ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+    if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+      anOperation->abort();
+
+    SessionPtr aMgr = ModelAPI_Session::get();
+    std::set<FeaturePtr> anIgnoredFeatures;
+    anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
+
+    QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
+    aMgr->startOperation(aName.toStdString());
+    aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
+    aMgr->finishOperation();
+  }
+  myCoinsideLines.clear();
+}
+
+
+void PartSet_MenuMgr::onDetachMenuHide()
+{
+  if (myPrevId != -1) {
+    // Restore color for previous object
+    setLineColor(myPrevId, myColor, false);
+  }
+  // Clear previous definitions
+  myPrevId = -1;
+}
+
+  
+void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
+{
+  ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+
+  bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
+                        PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
+  if (!isActiveSketch)
+    return;
+
+  QObjectPtrList anObjects;
+  bool isUseTransaction = false;
+  // 1. change auxiliary type of a created feature
+  if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
+      PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
+    anObjects.append(anOperation->feature());
+  }
+  else {
+    isUseTransaction = true;
+    // 2. change auxiliary type of selected sketch entities
+    ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+    anObjects = aSelection->selectedPresentations();
+  }
+
+  QAction* anAction = action("AUXILIARY_CMD");
+  SessionPtr aMgr = ModelAPI_Session::get();
+  if (isUseTransaction) {
+    if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+      anOperation->abort();
+    aMgr->startOperation(anAction->text().toStdString());
+  }
+  myModule->sketchMgr()->storeSelection();
+
+  if (anObjects.size() > 0) {
+    QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
+    for (; anIt != aLast; anIt++) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+      if (aFeature.get() != NULL) {
+        std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+        if (aSketchFeature.get() != NULL) {
+          std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
+
+          std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
+            std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
+          if (anAuxiliaryAttr)
+            anAuxiliaryAttr->setValue(isChecked);
+        }
+      }
+    }
+  }
+  if (isUseTransaction) {
+    aMgr->finishOperation();
+  }
+  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  myModule->sketchMgr()->restoreSelection();
+}
+
+bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
+{
+  bool anEnabled = false;
+  ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
+
+  bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
+                        PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
+  if (!isActiveSketch)
+    return anEnabled;
+
+  QObjectPtrList anObjects;
+  // 1. change auxiliary type of a created feature
+  if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
+      PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
+    anObjects.append(anOperation->feature());
+  }
+  else {
+    /// The operation should not be aborted here, because the method does not changed
+    /// the auxilliary state, but checks the possibility to perform this
+    ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
+    ///  anOperation->abort();
+    // 2. change auxiliary type of selected sketch entities
+    ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
+    anObjects = aSelection->selectedPresentations();
+  }
+  anEnabled = anObjects.size() > 0;
+
+  bool isNotAuxiliaryFound = false;
+  if (anObjects.size() > 0) {
+    QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
+    for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+      if (aFeature.get() != NULL) {
+        std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+        if (aSketchFeature.get() != NULL) {
+          std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
+
+          std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
+            std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
+          if (anAuxiliaryAttr)
+            isNotAuxiliaryFound = !anAuxiliaryAttr->value();
+        }
+      }
+    }
+  }
+  theValue = anObjects.size() && !isNotAuxiliaryFound;
+  return anEnabled;
+}
diff --git a/src/PartSet/PartSet_MenuMgr.h b/src/PartSet/PartSet_MenuMgr.h
new file mode 100644 (file)
index 0000000..1170986
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_MenuMgr.h
+// Created:     03 April 2015
+// Author:      Vitaly SMETANNIKOV
+
+#ifndef PartSet_MenuMgr_H
+#define PartSet_MenuMgr_H
+
+#include <ModelAPI_Feature.h>
+
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QList>
+#include <QColor>
+
+class PartSet_Module;
+class QAction;
+class QMenu;
+
+/**
+* \ingroup Modules
+* A class for management of module specific menu
+*/
+class PartSet_MenuMgr: public QObject
+{
+  Q_OBJECT
+public:
+  /// Constructor
+  /// \param theModule a parent module
+  PartSet_MenuMgr(PartSet_Module* theModule);
+
+
+  /// Returns action according to the given ID
+  /// \param theId an action identifier, it should be uniqued in the bounds of the module
+  QAction* action(const QString& theId) const;
+
+  /// Add menu atems for viewer into the given menu
+  /// \param theMenu a popup menu to be shown in the viewer
+  /// \param theStdActions a map of standard actions
+  /// \return true if items are added and there is no necessity to provide standard menu
+  bool addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const;
+
+public slots:
+  /// Processes the context menu action click
+  /// \param isChecked a state of toggle if the action is checkable
+  void onAction(bool isChecked);
+
+private slots:
+
+  /// A slot which is called on selection of menu item coresponding to line with coincedence
+  /// \param theAction an action of the selected item
+  void onLineHighlighted(QAction* theAction);
+
+  /// A slot which is called on hiding Detach menu
+  void onDetachMenuHide();
+
+  /// A slot which is called on selection an Item in Detach menu
+  /// \param theAction an action of the selected item
+  void onLineDetach(QAction* theAction);
+
+private:
+  /// Returns true if the current operation is sketch entity create operation
+  /// \param theValue the current auxiliary value
+  /// \return the boolean result
+  bool canSetAuxiliary(bool& theValue) const;
+  
+  /// Changes the sketcher entity construction argument value
+  /// \param isChecked if true, the feature is a construction
+  void setAuxiliary(const bool isChecked);
+
+  /// Create all actions for context menus. It is called on creation of module
+  /// Put the created actions into an internal map
+  void createActions();
+
+  /// Add action to the internal map
+  /// \param theId - string ID of the item
+  /// \param theAction - action to add
+  void addAction(const QString& theId, QAction* theAction);
+
+  /// Set color on presentation of result listed in myCoinsideLines
+  /// \param theId object Id in myCoinsideLines list
+  /// \param theColor a color which has to be set
+  /// \param theUpdate update viewer flag
+  /// \return previously defined color on the object
+  QColor setLineColor(int theId, const QColor theColor, bool theUpdate);
+
+  /// Reference to a parent module
+  PartSet_Module* myModule;
+
+  /// the popup menu actions
+  QMap<QString, QAction*> myActions; 
+
+  /// List of lines coincided in a one point
+  mutable QList<FeaturePtr> myCoinsideLines;
+
+  /// A Coincedence feature selected by user for detaching
+  mutable FeaturePtr mySelectedFeature;
+
+  /// Id of menu item in Detach menu previously selected
+  int myPrevId;
+
+  /// Original color of highlighted line 
+  QColor myColor;
+};
+
+#endif
\ No newline at end of file
index 4c685683578f2cd490d3964e314fca495da18414..3d22b28a7bd9f3891ee04352bf40ea4d475fd6c3 100644 (file)
@@ -8,7 +8,9 @@
 #include <PartSet_WidgetPoint2dDistance.h>
 #include <PartSet_WidgetShapeSelector.h>
 #include <PartSet_WidgetConstraintShapeSelector.h>
-#include <PartSet_SketcherMgr.h>
+#include <PartSet_WidgetEditor.h>
+#include "PartSet_SketcherMgr.h"
+#include "PartSet_MenuMgr.h"
 
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_IViewer.h>
@@ -50,8 +52,9 @@
 #include <SketchPlugin_Feature.h>
 #include <SketchPlugin_Sketch.h>
 #include <SketchPlugin_Line.h>
-//#include <SketchPlugin_Arc.h>
-//#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Point.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintDistance.h>
 #include <SketchPlugin_ConstraintParallel.h>
@@ -63,6 +66,7 @@
 
 #include <Events_Loop.h>
 #include <Config_PropManager.h>
+#include <Config_Keywords.h>
 
 #include <StdSelect_TypeOfFace.hxx>
 #include <TopoDS_Vertex.hxx>
@@ -112,7 +116,7 @@ PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop)
   connect(aViewer, SIGNAL(viewTransformed(int)),
           SLOT(onViewTransformed(int)));
 
-  createActions();
+  myMenuMgr = new PartSet_MenuMgr(this);
 }
 
 PartSet_Module::~PartSet_Module()
@@ -278,45 +282,19 @@ bool PartSet_Module::canRedo() const
 
 bool PartSet_Module::canDisplayObject(const ObjectPtr& theObject) const
 {
-  // the display should be possible almost always, with exception of some specific cases
-
-  bool aCanDisplay = true;
-
-  if (mySketchMgr->activeSketch()) {
-    aCanDisplay = mySketchMgr->canDisplayObject(theObject);
-  }
-  return aCanDisplay;
+  // the sketch manager put the restriction to the objects display
+  return mySketchMgr->canDisplayObject(theObject);
 }
 
+
 bool PartSet_Module::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
 {
-  ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
-  if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
-      !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
-    return false;
+  return myMenuMgr->addViewerItems(theMenu, theStdActions);
+}
 
-  ModuleBase_ISelection* aSelection = myWorkshop->selection();
-  QObjectPtrList aObjects = aSelection->selectedPresentations();
-  if (aObjects.size() > 0) {
-    bool hasFeature = false;
-    foreach(ObjectPtr aObject, aObjects)
-    {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
-      if (aFeature.get() != NULL) {
-        hasFeature = true;
-      }
-    }
-    if (hasFeature) {
-      theMenu->addAction(theStdActions["DELETE_CMD"]);
-    }
-  }
-  bool isAuxiliary;
-  if (mySketchMgr->canSetAuxiliary(isAuxiliary)) {
-    QAction* anAction = action("AUXILIARY_CMD");
-    theMenu->addAction(anAction);
-    anAction->setChecked(isAuxiliary);
-  }
-  return true;
+bool PartSet_Module::isMouseOverWindow()
+{
+  return mySketchMgr->isMouseOverWindow();
 }
 
 void PartSet_Module::propertyPanelDefined(ModuleBase_Operation* theOperation)
@@ -494,44 +472,12 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
       new PartSet_WidgetConstraintShapeSelector(theParent, workshop(), theWidgetApi, theParentId);
     aConstraintShapeSelectorWgt->setSketcher(mySketchMgr->activeSketch());
     aWgt = aConstraintShapeSelectorWgt;
-  }
+  } if (theType == WDG_DOUBLEVALUE_EDITOR) {
+    aWgt = new PartSet_WidgetEditor(theParent, workshop(), theWidgetApi, theParentId);
+  } 
   return aWgt;
 }
 
-void PartSet_Module::createActions()
-{
-  QAction* anAction;
-
-  anAction = new QAction(tr("Auxiliary"), this);
-  anAction->setCheckable(true);
-  addAction("AUXILIARY_CMD", anAction);
-}
-
-QAction* PartSet_Module::action(const QString& theId) const
-{
-  if (myActions.contains(theId))
-    return myActions[theId];
-  return 0;
-}
-
-void PartSet_Module::addAction(const QString& theId, QAction* theAction)
-{
-  if (myActions.contains(theId))
-    qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
-  theAction->setData(theId);
-  connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
-  myActions[theId] = theAction;
-}
-
-void PartSet_Module::onAction(bool isChecked)
-{
-  QAction* aAction = static_cast<QAction*>(sender());
-  QString anId = aAction->data().toString();
-
-  if (anId == "AUXILIARY_CMD") {
-    mySketchMgr->setAuxiliary(isChecked);
-  }
-}
 
 bool PartSet_Module::deleteObjects()
 {
@@ -547,7 +493,7 @@ bool PartSet_Module::deleteObjects()
   // the abort leads to selection lost on constraint objects. It can be corrected after #386 issue
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
   XGUI_Workshop* aWorkshop = aConnector->workshop();
-  ModuleBase_ISelection* aSel = aConnector->selection();
+  ModuleBase_ISelection* aSel = workshop()->selection();
   QObjectPtrList aSelectedObj = aSel->selectedPresentations();
   // if there are no selected objects in the viewer, that means that the selection in another
   // place cased this method. It is necessary to return the false value to understande in above
index 5264352dc98b0563d12877f826f862cce2cd67dd..fe5387240c0cf2ccd17716073bd453a6b4968558 100644 (file)
@@ -5,7 +5,6 @@
 
 #include "PartSet.h"
 #include "PartSet_Filters.h"
-#include "PartSet_SketcherMgr.h"
 
 #include <ModuleBase_IModule.h>
 #include <ModuleBase_Definitions.h>
@@ -26,6 +25,8 @@
 
 class ModuleBase_Operation;
 class ModuleBase_IViewWindow;
+class PartSet_MenuMgr;
+class PartSet_SketcherMgr;
 
 class QAction;
 
@@ -83,10 +84,6 @@ public:
   /// \param theOperation a started operation
   virtual ModuleBase_Operation* currentOperation() const;
 
-  /// Returns action according to the given ID
-  /// \param theId an action identifier, it should be uniqued in the bounds of the module
-  QAction* action(const QString& theId) const;
-
   /// Returns True if there are available Undos and the sketch manager allows undo
   /// \return the boolean result
   virtual bool canUndo() const;
@@ -107,15 +104,17 @@ public:
   /// \return true if items are added and there is no necessity to provide standard menu
   virtual bool addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const;
 
+  /// Returns whether the mouse enter the viewer's window
+  /// \return true if items are added and there is no necessity to provide standard menu
+  bool isMouseOverWindow();
+
+  PartSet_SketcherMgr* sketchMgr() const { return mySketchMgr; }
+
 public slots:
   /// SLOT, that is called by no more widget signal emitted by property panel
   /// Set a specific flag to restart the sketcher operation
   void onNoMoreWidgets();
 
-  /// Processes the context menu action click
-  /// \param isChecked a state of toggle if the action is checkable
-  void onAction(bool isChecked);
-
   /// Slolt called on object display
   /// \param theObject a data object
   /// \param theAIS a presentation object
@@ -160,15 +159,6 @@ protected slots:
   /// Breaks sequense of automatically resterted operations
   void breakOperationSequence();
 
-  /// Create all actions for context menus. It is called on creation of module
-  /// Put the created actions into an internal map
-  void createActions();
-
-  /// Add action to the internal map
-  /// \param theId - string ID of the item
-  /// \param theAction - action to add
-  void addAction(const QString& theId, QAction* theAction);
-
   //! Delete features
   virtual bool deleteObjects();
 
@@ -184,7 +174,7 @@ protected slots:
 
   PartSet_SketcherMgr* mySketchMgr;
 
-  QMap<QString, QAction*> myActions; // the popup menu actions
+  PartSet_MenuMgr* myMenuMgr;
 
   int myVisualLayerId;
 };
index 10a008fee15c704a0984a6c693dbbedf449301ed..359ee319e664327a795cd3f50fb7ba48ddc55763 100644 (file)
@@ -776,152 +776,49 @@ bool PartSet_SketcherMgr::canRedo() const
 bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
 {
   bool aCanDisplay = true;
-  // 1. the sketch feature should not be displayed during the sketch active operation
-  // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch 
-  // nested features can be visualized
-  CompositeFeaturePtr aSketchFeature = activeSketch();
-  if (aSketchFeature.get() != NULL) {
+
+  bool aHasActiveSketch = activeSketch().get() != NULL;
+  if (aHasActiveSketch) {
+    // 1. the sketch feature should not be displayed during the sketch active operation
+    // it is hidden by a sketch operation start and shown by a sketch stop, just the sketch 
+    // nested features can be visualized
     FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
-    if (aFeature.get() != NULL && aFeature == aSketchFeature)
+    if (aFeature.get() != NULL && aFeature == activeSketch())
       aCanDisplay = false;
   }
-  // 2. For created nested feature operation do not display the created feature if
+  else { // there are no an active sketch
+    // 2. sketch sub-features should not visualized if the sketch operatio is not active
+    FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+    if (aFeature.get() != NULL) {
+      std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                              std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+      if (aSketchFeature.get())
+        aCanDisplay = false;
+    }
+  }
+
+  // 3. For created nested feature operation do not display the created feature if
   // the mouse curstor leaves the OCC window.
   // The correction cases, which ignores this condition:
   // a. the property panel values modification
   // b. the popup menu activated
   // c. widget editor control
-  if (aCanDisplay) {
-    if (!isNestedCreateOperation(getCurrentOperation()))
-      return aCanDisplay;
-
+  if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
     ModuleBase_Operation* aOperation = getCurrentOperation();
     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
     ModuleBase_ModelWidget* anActiveWdg = aPanel ? aPanel->activeWidget() : 0;
+    ModuleBase_WidgetEditor* anEditorWdg = anActiveWdg ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWdg) : 0;
     // the active widget editor should not influence here. The presentation should be visible always
     // when this widget is active.
-    if (anActiveWdg) {
-      ModuleBase_WidgetEditor* anEditorWdg = dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWdg);
-      if (anEditorWdg) {
-        return aCanDisplay;
-      }
+    if (!anEditorWdg && !myIsPopupMenuActive) {
+      // during a nested create operation, the feature is redisplayed only if the mouse over view
+      // of there was a value modified in the property panel after the mouse left the view
+      aCanDisplay = myIsPropertyPanelValueChanged || myIsMouseOverWindow;
     }
-    if (myIsPopupMenuActive)
-      return aCanDisplay;
-
-    // during a nested create operation, the feature is redisplayed only if the mouse over view
-    // of there was a value modified in the property panel after the mouse left the view
-    aCanDisplay = myIsPropertyPanelValueChanged || myIsMouseOverWindow;
   }
   return aCanDisplay;
 }
 
-bool PartSet_SketcherMgr::canSetAuxiliary(bool& theValue) const
-{
-  bool anEnabled = false;
-  ModuleBase_Operation* anOperation = getCurrentOperation();
-
-  bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
-                        PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
-  if (!isActiveSketch)
-    return anEnabled;
-
-  QObjectPtrList anObjects;
-  // 1. change auxiliary type of a created feature
-  if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
-      PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
-    anObjects.append(anOperation->feature());
-  }
-  else {
-    /// The operation should not be aborted here, because the method does not changed
-    /// the auxilliary state, but checks the possibility to perform this
-    ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
-    ///  anOperation->abort();
-    // 2. change auxiliary type of selected sketch entities
-    ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
-    anObjects = aSelection->selectedPresentations();
-  }
-  anEnabled = anObjects.size() > 0;
-
-  bool isNotAuxiliaryFound = false;
-  if (anObjects.size() > 0) {
-    QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
-    for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
-      if (aFeature.get() != NULL) {
-        std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
-                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-        if (aSketchFeature.get() != NULL) {
-          std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
-
-          std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
-            std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
-          if (anAuxiliaryAttr)
-            isNotAuxiliaryFound = !anAuxiliaryAttr->value();
-        }
-      }
-    }
-  }
-  theValue = anObjects.size() && !isNotAuxiliaryFound;
-  return anEnabled;
-}
-  
-void PartSet_SketcherMgr::setAuxiliary(const bool isChecked)
-{
-  ModuleBase_Operation* anOperation = getCurrentOperation();
-
-  bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
-                        PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
-  if (!isActiveSketch)
-    return;
-
-  QObjectPtrList anObjects;
-  bool isUseTransaction = false;
-  // 1. change auxiliary type of a created feature
-  if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
-      PartSet_SketcherMgr::isEntityOperation(anOperation) ) {
-    anObjects.append(anOperation->feature());
-  }
-  else {
-    isUseTransaction = true;
-    // 2. change auxiliary type of selected sketch entities
-    ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
-    anObjects = aSelection->selectedPresentations();
-  }
-
-  QAction* anAction = myModule->action("AUXILIARY_CMD");
-  SessionPtr aMgr = ModelAPI_Session::get();
-  if (isUseTransaction) {
-    if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
-      anOperation->abort();
-    aMgr->startOperation(anAction->text().toStdString());
-  }
-  storeSelection();
-
-  if (anObjects.size() > 0) {
-    QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
-    for (; anIt != aLast; anIt++) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
-      if (aFeature.get() != NULL) {
-        std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
-                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-        if (aSketchFeature.get() != NULL) {
-          std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
-
-          std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
-            std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
-          if (anAuxiliaryAttr)
-            anAuxiliaryAttr->setValue(isChecked);
-        }
-      }
-    }
-  }
-  if (isUseTransaction) {
-    aMgr->finishOperation();
-  }
-  Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
-  restoreSelection();
-}
 
 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
 {
index aad09ef0fda92803c1694ca56c514e79711aad5b..01789c136b6e4a46054a215006aadffb5aa58e14 100644 (file)
@@ -102,6 +102,8 @@ public:
   /// \return a boolean value
   static bool isDistanceOperation(ModuleBase_Operation* theOperation);
 
+  bool isMouseOverWindow() { return myIsMouseOverWindow; }
+
   /// Returns current Sketch feature/ Returns NULL if there is no launched sketch operation
   CompositeFeaturePtr activeSketch() const { return myCurrentSketch; }
 
@@ -137,18 +139,14 @@ public:
   /// \param theObject a model object
   bool canDisplayObject(const ObjectPtr& theObject) const;
 
-  /// Returns true if the current operation is sketch entity create operation
-  /// \param theValue the current auxiliary value
-  /// \return the boolean result
-  bool canSetAuxiliary(bool& theValue) const;
-  
-  /// Changes the sketcher entity construction argument value
-  /// \param isChecked if true, the feature is a construction
-  void setAuxiliary(const bool isChecked);
-
-
+  /// Returns state of constraints showing flag 
   bool isConstraintsShown() const { return myIsConstraintsShown; }
 
+  /// Saves the current selection in the viewer into an internal container
+  /// It obtains the selected attributes. The highlighted objects can be processes as the selected ones
+  /// \param theHighlightedUse a boolean flag
+  void storeSelection(const bool theHighlightedOnly = false);
+  void restoreSelection();
 
   /// Returns list of strings which contains id's of sketch operations
   static const QStringList& sketchOperationIdList();
@@ -248,12 +246,6 @@ private:
   /// \param isToDisplay a flag about the display or erase the feature
   void visualizeFeature(ModuleBase_Operation* theOperation, const bool isToDisplay);
 
-  /// Saves the current selection in the viewer into an internal container
-  /// It obtains the selected attributes. The highlighted objects can be processes as the selected ones
-  /// \param theHighlightedUse a boolean flag
-  void storeSelection(const bool theHighlightedOnly = false);
-  void restoreSelection();
-
 private:
   PartSet_Module* myModule;
 
diff --git a/src/PartSet/PartSet_WidgetEditor.cpp b/src/PartSet/PartSet_WidgetEditor.cpp
new file mode 100644 (file)
index 0000000..66ed150
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_WidgetShapeSelector.cpp
+// Created:     27 Nov 2014
+// Author:      Vitaly Smetannikov
+
+#include "PartSet_WidgetEditor.h"
+#include "PartSet_Module.h"
+
+#include <ModuleBase_IWorkshop.h>
+
+#include <Config_WidgetAPI.h>
+
+#include <QWidget>
+
+PartSet_WidgetEditor::PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                                           const Config_WidgetAPI* theData,
+                                           const std::string& theParentId)
+ : ModuleBase_WidgetEditor(theParent, theData, theParentId), myWorkshop(theWorkshop)
+{
+}
+
+bool PartSet_WidgetEditor::focusTo()
+{
+  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+  if (aModule->isMouseOverWindow())
+    return ModuleBase_WidgetDoubleValue::focusTo();
+  else {
+    ModuleBase_WidgetEditor::focusTo();
+  }
+}
diff --git a/src/PartSet/PartSet_WidgetEditor.h b/src/PartSet/PartSet_WidgetEditor.h
new file mode 100644 (file)
index 0000000..a4f6111
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        PartSet_WidgetShapeSelector.h
+// Created:     27 Nov 2014
+// Author:      Vitaly Smetannikov
+
+
+#ifndef PartSet_WidgetEditor_H
+#define PartSet_WidgetEditor_H
+
+#include "PartSet.h"
+
+#include <ModuleBase_WidgetEditor.h>
+
+class ModuleBase_IWorkshop;
+
+/**
+* \ingroup Modules
+* Customosation of ModuleBase_WidgetEditor in order to do not show the editor value if the mouse
+* cursor is not over the OCC window
+*/
+class PARTSET_EXPORT PartSet_WidgetEditor : public ModuleBase_WidgetEditor
+{
+Q_OBJECT
+ public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theWorkshop instance of workshop interface
+  /// \param theData the widget configuation. The attribute of the model widget is obtained from
+  /// \param theParentId is Id of a parent of the current attribute
+  PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                       const Config_WidgetAPI* theData, const std::string& theParentId);
+
+  virtual ~PartSet_WidgetEditor() {}
+
+  /// Activates the editor control only in case if the mouse over the OCC window, otherwise
+  /// set focus to the usual double value control
+  /// \return the state whether the widget can accept the focus
+  virtual bool focusTo();
+
+private:
+  ModuleBase_IWorkshop* myWorkshop; // the current workshop
+};
+
+#endif
\ No newline at end of file
index 1b645c062821a47d4190355106ae8cb9fa8989a1..6be038d19d803a84cf839d7dc1e6e7e97e6e7f7f 100644 (file)
@@ -27,6 +27,7 @@
 #include <GeomAPI_XYZ.h>
 
 #include <SketchPlugin_Sketch.h>
+#include <SketcherPrs_Tools.h>
 
 #include <Precision.hxx>
 #include <gp_Pln.hxx>
@@ -360,8 +361,9 @@ void PartSet_WidgetSketchLabel::setSketchingMode()
 
   // Get default selection modes
   QIntList aModes;
-  aModes.append(AIS_DSM_Text);
-  aModes.append(AIS_DSM_Line);
+  aModes.append(SketcherPrs_Tools::Sel_Dimension_Text);
+  aModes.append(SketcherPrs_Tools::Sel_Dimension_Line);
+  aModes.append(SketcherPrs_Tools::Sel_Constraint);
   aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_VERTEX));
   aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum) TopAbs_EDGE));
 
index 62abd9eef9f3dd643fa9de391f78bea3c6c92f03..49f98b0cfb4983daacf7095704474f8d9acd49f6 100644 (file)
@@ -84,4 +84,6 @@ class SketchPlugin_Constraint : public SketchPlugin_Feature
   }
 };
 
+typedef std::shared_ptr<SketchPlugin_Constraint> ConstraintPtr;
+
 #endif
index a78e1b4efc2d0b7b0aeddfc959586679345ecb63..ce8fa25de2daa4b3f1637189d2bf912210e683ef 100644 (file)
@@ -36,7 +36,9 @@ AISObjectPtr SketchPlugin_ConstraintCoincidence::getAISObject(AISObjectPtr thePr
   AISObjectPtr anAIS = thePrevious;
   if (!anAIS) {
     anAIS = SketcherPrs_Factory::coincidentConstraint(this, sketch()->coordinatePlane());
-    anAIS->setColor(0, 0, 255);
+  std::vector<int> aRGB = Config_PropManager::color("Visualization", "sketch_constraint_color",
+                                                    SKETCH_DIMENSION_COLOR);
+  anAIS->setColor(aRGB[0], aRGB[1], aRGB[2]);
   }
   return anAIS;
 }
index 59ca35b02cc6fcebf2681d99929a8219f415238f..b7f708a9c59578efdec9e6d06e6b9690e1c46058 100644 (file)
@@ -82,19 +82,19 @@ bool SketchPlugin_ConstraintDistance::compute(const std::string& theAttributeId)
     aPnt_A = aPoint_A->pnt();
     aPnt_B = aPoint_B->pnt();
   } else if (!aPoint_A && aPoint_B) {
-    std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
-        aData, SketchPlugin_Constraint::ENTITY_A());
-    if (aLine) {
-      aPnt_B = aPoint_B->pnt();
-      aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
-    }
+    //std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+    //    aData, SketchPlugin_Constraint::ENTITY_A());
+    //if (aLine) {
+    //  aPnt_B = aPoint_B->pnt();
+    //  aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
+    //}
   } else if (aPoint_A && !aPoint_B) {
-    std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
-        aData, SketchPlugin_Constraint::ENTITY_B());
-    if (aLine) {
-      aPnt_A = aPoint_A->pnt();
-      aPnt_B = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_A);
-    }
+    //std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+    //    aData, SketchPlugin_Constraint::ENTITY_B());
+    //if (aLine) {
+    //  aPnt_A = aPoint_A->pnt();
+    //  aPnt_B = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_A);
+    //}
   }
   if (!aPnt_A || !aPnt_B)
     return false;
@@ -159,19 +159,19 @@ double SketchPlugin_ConstraintDistance::calculateCurrentDistance() const
   if (aPointA && aPointB) {  // both points
     aDistance = aPointA->pnt()->distance(aPointB->pnt());
   } else {
-    if (!aPointA && aPointB) {  //Line and point
-      std::shared_ptr<SketchPlugin_Line> aLine =
-          SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
-      if (aLine) {
-        aDistance = aLine->distanceToPoint(aPointB->pnt());
-      }
-    } else if (aPointA && !aPointB) {  // Point and line
-      std::shared_ptr<SketchPlugin_Line> aLine =
-          SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
-      if (aLine) {
-        aDistance = aLine->distanceToPoint(aPointA->pnt());
-      }
-    }
+//    if (!aPointA && aPointB) {  //Line and point
+//      std::shared_ptr<SketchPlugin_Line> aLine =
+//          SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
+//      if (aLine) {
+//        aDistance = aLine->distanceToPoint(aPointB->pnt());
+//      }
+//    } else if (aPointA && !aPointB) {  // Point and line
+//      std::shared_ptr<SketchPlugin_Line> aLine =
+//          SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+//      if (aLine) {
+//        aDistance = aLine->distanceToPoint(aPointA->pnt());
+//      }
+//    }
   }
   return aDistance;
 }
index 79cac01e7d10411a328c68a2db727a9f3eb7e2ae..7d8e142bc50f6acdba6ba42ad85eee6feff188ce 100644 (file)
@@ -30,6 +30,8 @@
 #include <Config_PropManager.h>
 #include <Events_Loop.h>
 
+static const std::string PREVIOUS_VALUE("FilletPreviousRadius");
+
 /// \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);
@@ -45,8 +47,11 @@ void SketchPlugin_ConstraintFillet::initAttributes()
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
+  data()->addAttribute(PREVIOUS_VALUE, ModelAPI_AttributeDouble::typeId());
   // initialize attribute not applicable for user
   data()->attribute(SketchPlugin_Constraint::ENTITY_C())->setInitialized();
+  data()->attribute(PREVIOUS_VALUE)->setInitialized();
+  std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(data()->attribute(PREVIOUS_VALUE))->setValue(0.0);
 }
 
 void SketchPlugin_ConstraintFillet::execute()
@@ -87,9 +92,17 @@ void SketchPlugin_ConstraintFillet::execute()
       FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : 
         std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
       if (aFeature == aFilletArcFeature) {
-        AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-            aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
-        aRadius->setValue(aFilletRadius);
+        // Update radius constraint only if the value is changed in fillet's attribute
+        double aPrevRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+            aData->attribute(PREVIOUS_VALUE))->value();
+        if (aFilletRadius != aPrevRadius) {
+          AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+              aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
+          aRadius->setValue(aFilletRadius);
+          std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+              aData->attribute(PREVIOUS_VALUE))->setValue(aFilletRadius);
+        }
+        break;
       }
     }
     return;
@@ -108,16 +121,14 @@ void SketchPlugin_ConstraintFillet::execute()
   FeaturePtr aNewFeatureA = sketch()->addFeature(aFeatureA->getKind());
   aFeatureA->data()->copyTo(aNewFeatureA->data());
   aNewFeatureA->execute();
-  aRefListOfFillet->append(aNewFeatureA);
+  aRefListOfFillet->append(aNewFeatureA->firstResult());
   // copy aFeatureB
   FeaturePtr aNewFeatureB = sketch()->addFeature(aFeatureB->getKind());
   aFeatureB->data()->copyTo(aNewFeatureB->data());
   aNewFeatureB->execute();
-  aRefListOfFillet->append(aNewFeatureB);
-  // create filleting arc
+  aRefListOfFillet->append(aNewFeatureB->firstResult());
+  // create filleting arc (it will be attached to the list later)
   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);
@@ -203,11 +214,14 @@ void SketchPlugin_ConstraintFillet::execute()
       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());
+      aSharedPoint->x() - 1.e-5 * aStep->y(), aSharedPoint->y() + 1.e-5 * aStep->x());
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(
-      aCenter->x() + aStep->y(), aCenter->y() - aStep->x());
+      aSharedPoint->x() + 1.e-5 * aStep->y(), aSharedPoint->y() - 1.e-5 * aStep->x());
   aNewArc->execute();
+  // attach new arc to the list
+  aRefListOfFillet->append(aNewArc->lastResult());
+  aRefListOfFillet->setInitialized();
 
   // Create list of additional constraints:
   // 1. Coincidence of boundary points of features and fillet arc
index 5dc94ef4a28b5e38b00440fc1dc9daebeae646de..fd765dec9fb452fbc9e13b89f07a32b7e43fe460 100644 (file)
@@ -11,6 +11,7 @@
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Events.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 
@@ -90,6 +91,8 @@ void SketchPlugin_ConstraintMirror::execute()
       aMirrorIter++;
   }
 
+  static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
+
   // Check consistency of initial list and mirrored list
   anInitialList =  aRefListOfShapes->list();
   anInitIter = anInitialList.begin();
@@ -131,6 +134,7 @@ void SketchPlugin_ConstraintMirror::execute()
       FeaturePtr aNewFeature = sketch()->addFeature(aFeatureIn->getKind());
       aFeatureIn->data()->copyTo(aNewFeature->data());
       aNewFeature->execute();
+      ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
 
       std::shared_ptr<GeomAPI_Shape> aShapeIn = aRCIn->shape();
       const std::list<ResultPtr>& aResults = aNewFeature->results();
index 741674a5b9429e461ffa6cf1da6bbca6f7d00029..8867e16d55932720530b9e6e0ea9dde72eeb88b6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "SketchPlugin_ConstraintRigid.h"
 #include "SketchPlugin_ConstraintParallel.h"
+#include "SketchPlugin_Feature.h"
 
 #include <SketcherPrs_Factory.h>
 
@@ -34,8 +35,18 @@ AISObjectPtr SketchPlugin_ConstraintRigid::getAISObject(AISObjectPtr thePrevious
     return thePrevious;
 
   AISObjectPtr anAIS = thePrevious;
-  if (!anAIS) {
-    anAIS = SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane());
+  if (anAIS.get() == NULL) {
+    std::shared_ptr<ModelAPI_Data> aData = data();
+    std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
+      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
+    ObjectPtr aObj = anAttr->object();
+    if (aObj.get() != NULL) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
+      std::shared_ptr<SketchPlugin_Feature> aSkFea = 
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+      if (!aSkFea->isExternal()) 
+        anAIS = SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane());
+    }
   }
 
   return anAIS;
index ed07e4079bd6bd7eba234a943289ec1d97b6539e..555b8ae7f4e18e85e3d490e5537bd7a6fd2c899e 100644 (file)
@@ -100,6 +100,12 @@ double SketchPlugin_Line::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>&
   return aDelta;
 }
 
+const std::string& SketchPlugin_Line::getKind()
+{
+  static std::string MY_KIND = SketchPlugin_Line::ID();
+  return MY_KIND;
+}
+
 bool SketchPlugin_Line::isFixed() {
   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
 }
index 05d94cc65e59bd582bd6290920a1d7820d995e4a..f6d895974b981354c6eda92f0ba9c2f95f4a2dd8 100644 (file)
@@ -39,11 +39,7 @@ class SketchPlugin_Line : public SketchPlugin_SketchEntity
   }
 
   /// Returns the kind of a feature
-  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
-  {
-    static std::string MY_KIND = SketchPlugin_Line::ID();
-    return MY_KIND;
-  }
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind();
 
   /// Returns true is sketch element is under the rigid constraint
   SKETCHPLUGIN_EXPORT virtual bool isFixed();
index caeb92d8d45f78528ad6fc4854d353f8f49fb901..f2bce5f32c89d4c47fcb6adccf7b9319ddf56be4 100644 (file)
             label="Last object" tooltip="Select line or arc" shape_types="edge">
         </sketch_constraint_shape_selector>
 
-        <doublevalue_editor label="Value" tooltip="Fillet radius" id="ConstraintValue" default="1" min="0" obligatory="0">
+        <doublevalue_editor label="Value" tooltip="Fillet radius" id="ConstraintValue" min="0">
           <validator id="GeomValidators_Positive"/>
         </doublevalue_editor>
       </feature>
index 572c8b0c797aec82193cc5bfea5242b5bdc1fbff..d8070e05f68e641d867a06d03615301154c05efe 100644 (file)
@@ -5,17 +5,40 @@ INCLUDE(FindSolveSpace)
 
 SET(PROJECT_HEADERS
     SketchSolver.h
+    SketchSolver_Error.h
     SketchSolver_Solver.h
     SketchSolver_Constraint.h
-    SketchSolver_ConstraintGroup.h
+    SketchSolver_ConstraintCoincidence.h
+    SketchSolver_ConstraintDistance.h
+    SketchSolver_ConstraintEqual.h
+    SketchSolver_ConstraintFillet.h
+    SketchSolver_ConstraintLength.h
+    SketchSolver_ConstraintMirror.h
+    SketchSolver_ConstraintRigid.h
+    SketchSolver_ConstraintTangent.h
+    SketchSolver_Builder.h
+    SketchSolver_Group.h
     SketchSolver_ConstraintManager.h
+    SketchSolver_Storage.h
+    SketchSolver_FeatureStorage.h
 )
 
 SET(PROJECT_SOURCES
     SketchSolver_Solver.cpp
     SketchSolver_Constraint.cpp
-    SketchSolver_ConstraintGroup.cpp
+    SketchSolver_ConstraintCoincidence.cpp
+    SketchSolver_ConstraintDistance.cpp
+    SketchSolver_ConstraintEqual.cpp
+    SketchSolver_ConstraintFillet.cpp
+    SketchSolver_ConstraintLength.cpp
+    SketchSolver_ConstraintMirror.cpp
+    SketchSolver_ConstraintRigid.cpp
+    SketchSolver_ConstraintTangent.cpp
+    SketchSolver_Builder.cpp
+    SketchSolver_Group.cpp
     SketchSolver_ConstraintManager.cpp
+    SketchSolver_Storage.cpp
+    SketchSolver_FeatureStorage.cpp
 )
 
 SET(PROJECT_LIBRARIES
index f31b7e49f65076ca43234ad50f1a5f5c1b50b258..77bb4029a701f8a8faa5e6174cad5cdba5e0195b 100644 (file)
@@ -17,4 +17,7 @@
 #endif
 #endif
 
+/// Tolerance for value of parameters
+const double tolerance = 1.e-10;
+
 #endif
diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp
new file mode 100644 (file)
index 0000000..82cf966
--- /dev/null
@@ -0,0 +1,308 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include "SketchSolver_Builder.h"
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_ConstraintDistance.h>
+#include <SketchSolver_ConstraintEqual.h>
+#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_ConstraintLength.h>
+#include <SketchSolver_ConstraintMirror.h>
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_ConstraintTangent.h>
+#include <SketchSolver_Error.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <Events_Error.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
+#include <math.h>
+
+// Initialization of constraint builder self pointer
+SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
+
+SketchSolver_Builder* SketchSolver_Builder::getInstance()
+{
+  if (!mySelf)
+    mySelf = new SketchSolver_Builder();
+  return mySelf;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+{
+  SolverConstraintPtr aResult;
+  DataPtr aData = theConstraint->data();
+  if (!aData || !aData->isValid())
+    return aResult;
+
+#ifdef _DEBUG
+  // Verify attributes of constraint and generate errors
+  std::list<AttributePtr> anAttrList = aData->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+  for (; anIter != anAttrList.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (aRefAttr->isObject() && aRefAttr->object()) {
+        ResultConstructionPtr aRC =
+            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aRefAttr->object());
+        if (!aRC)
+          Events_Error::send(SketchSolver_Error::NEED_OBJECT_NOT_FEATURE(), this);
+      }
+      continue;
+    }
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+    if (aRefList) {
+      std::list<ObjectPtr> aList = aRefList->list();
+      std::list<ObjectPtr>::iterator aListIter = aList.begin();
+      for (; aListIter != aList.end(); aListIter++) {
+        ResultConstructionPtr aRC =
+            std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aListIter);
+        if (*aListIter && !aRC)
+          Events_Error::send(SketchSolver_Error::NEED_OBJECT_NOT_FEATURE(), this);
+      }
+    }
+  }
+#endif
+
+  if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
+  } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
+    return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+  }
+  return aResult;
+}
+
+SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+{
+  DataPtr aData = theFixedFeature->data();
+  if (!aData || !aData->isValid())
+    return SolverConstraintPtr();
+  return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+}
+
+
+
+bool SketchSolver_Builder::createWorkplane(
+    CompositeFeaturePtr theSketch,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  DataPtr aSketchData = theSketch->data();
+  if (!aSketchData || !aSketchData->isValid())
+    return false; // the sketch is incorrect
+
+  // Get parameters of workplane
+  std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
+      SketchPlugin_Sketch::DIRX_ID());
+  std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
+      SketchPlugin_Sketch::NORM_ID());
+  std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
+      SketchPlugin_Sketch::ORIGIN_ID());
+  // Create SolveSpace entity corresponding to the sketch origin
+  if (!createEntity(anOrigin, theEntities, theParameters))
+    return false;
+  Slvs_hEntity anOriginID = theEntities.back().h;
+  // Create SolveSpace entity corresponding the the sketch normal
+  if (!createNormal(aNorm, aDirX, theEntities, theParameters))
+    return false;
+  Slvs_hEntity aNormalID = theEntities.back().h;
+
+  // Create workplane
+  Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
+  Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
+  theEntities.push_back(aWorkplane);
+  return true;
+}
+
+bool SketchSolver_Builder::createEntity(
+    AttributePtr theAttribute,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
+  Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
+
+  // Point in 3D
+  std::shared_ptr<GeomDataAPI_Point> aPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+  if (aPoint) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
+    theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
+        aParamID-2, aParamID-1, aParamID));
+    return true;
+  }
+  // Point in 2D
+  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  if (aPoint2D) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
+    theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+      aParamID-1, aParamID));
+    return true;
+  }
+  // Scalar value (used for the distance entities)
+  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+  if (aScalar) {
+    theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
+    theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
+      SLVS_E_UNKNOWN, aParamID));
+    return true;
+  }
+  // unknown attribute type
+  return false;
+}
+
+bool SketchSolver_Builder::createEntity(
+    FeaturePtr theFeature,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  if (!theFeature->data()->isValid())
+    return false;
+
+  // SketchPlugin features
+  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
+      SketchPlugin_Feature>(theFeature);
+  if (!aFeature)
+    return false;
+
+  // Verify the feature by its kind
+  const std::string& aFeatureKind = aFeature->getKind();
+  DataPtr aData = aFeature->data();
+  // Line
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
+    AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
+    if (!aStart->isInitialized() || !aEnd->isInitialized())
+      return false;
+    if (!createEntity(aStart, theEntities, theParameters) ||
+        !createEntity(aEnd, theEntities, theParameters))
+      return false;
+    Slvs_hEntity aLineID = theEntities.back().h + 1;
+    theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+        aLineID-2, aLineID-1));
+  }
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+    AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+    AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+    if (!aCenter->isInitialized() || !aRadius->isInitialized())
+      return false;
+    if (!createEntity(aCenter, theEntities, theParameters) ||
+        !createEntity(aRadius, theEntities, theParameters))
+      return false;
+    Slvs_hEntity aCircID = theEntities.back().h;
+    theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
+      SLVS_E_UNKNOWN, aCircID-1));
+  }
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+    AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
+    AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
+    if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
+      return false;
+    if (!createEntity(aCenter, theEntities, theParameters) ||
+        !createEntity(aStart, theEntities, theParameters) ||
+        !createEntity(aEnd, theEntities, theParameters))
+      return false;
+    Slvs_hEntity anArcID = theEntities.back().h;
+    theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
+        SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
+  }
+  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+  else if (aFeatureKind == SketchPlugin_Point::ID()) {
+    AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID());
+    if (!aPoint->isInitialized() ||
+        !createEntity(aPoint, theEntities, theParameters))
+      return false;
+    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
+    // No need to add another entity.
+  }
+  return true;
+}
+
+bool SketchSolver_Builder::createNormal(
+    AttributePtr theNormal,
+    AttributePtr theDirX,
+    std::vector<Slvs_Entity>& theEntities,
+    std::vector<Slvs_Param>& theParameters)
+{
+  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
+  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+  if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
+    return false;
+  // calculate Y direction
+  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
+
+  // quaternion parameters of normal vector
+  double qw, qx, qy, qz;
+  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
+                      &qx, &qy, &qz);
+  double aNormCoord[4] = { qw, qx, qy, qz };
+
+  // Create parameters of the normal
+  Slvs_hParam aCurParam = theParameters.back().h;
+  for (int i = 0; i < 4; i++)
+    theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
+
+  // Create a normal
+  Slvs_hEntity aCurEntity = theEntities.back().h + 1;
+  Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
+      aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
+  theEntities.push_back(aNormal);
+  return true;
+}
diff --git a/src/SketchSolver/SketchSolver_Builder.h b/src/SketchSolver/SketchSolver_Builder.h
new file mode 100644 (file)
index 0000000..e9aa10d
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Builder.h
+// Created: 25 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Builder_H_
+#define SketchSolver_Builder_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class   SketchSolver_Builder
+ *  \ingroup Plugins
+ *  \brief   Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SketchSolver_Builder
+{
+private:
+  /// Default constructor
+  SketchSolver_Builder() {}
+
+public:
+  /// \brief Returns single instance of builder
+  static SketchSolver_Builder* getInstance();
+
+  /// \brief Creates a solver's constraint using given SketchPlugin constraint
+  ///        or returns empty pointer if not all attributes are correct
+  SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+
+  /// \brief Creates temporary constraint to fix the placement of the feature
+  SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+
+  /// \brief Converts sketch parameters to the list of SolveSpace entities.
+  ///        Identifiers of entities and parameters are local. They should be changed while adding into storage.
+  ///        The sketch entity goes last.
+  /// \param[in]  theSketch     the element to be converted
+  /// \param[out] theEntities   created list of entities
+  /// \param[out] theParameters created list of parameters of the entities
+  /// \return \c true if workplane created
+  bool createWorkplane(CompositeFeaturePtr theSketch,
+                       std::vector<Slvs_Entity>& theEntities,
+                       std::vector<Slvs_Param>& theParameters);
+
+  /// \brief Converts attribute to the list of entities.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createEntity(AttributePtr theAttribute,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+  /// \brief Converts feature to the list of entities.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createEntity(FeaturePtr theFeature,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+
+  /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
+  ///        Identifiers are local (see createWorkplane).
+  ///        The main entity goes last.
+  bool createNormal(AttributePtr theNormal,
+                    AttributePtr theDirX,
+                    std::vector<Slvs_Entity>& theEntities,
+                    std::vector<Slvs_Param>& theParameters);
+
+private:
+  static SketchSolver_Builder* mySelf;
+};
+
+#endif
index 3c5b4be1b8cb72478c378cd2b538b7154043a825..370bdce0d4e4962f6ac7f2d8635e077c91769383 100644 (file)
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_Constraint.cpp
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_Constraint.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
 
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintDistance.h>
-#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Shape.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultConstruction.h>
 
-/// Possible types of attributes (used to determine constraint type)
-enum AttrType
+#include <math.h>
+
+SketchSolver_Constraint::SketchSolver_Constraint(
+    ConstraintPtr  theConstraint)
+  : myBaseConstraint(theConstraint),
+    myGroup(0)
 {
-  UNKNOWN,  // Something wrong during type determination
-  POINT2D,
-  POINT3D,
-  LINE,
-  CIRCLE,
-  ARC
-};
-
-/// Calculate type of the attribute
-static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
-
-SketchSolver_Constraint::SketchSolver_Constraint()
-    : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
-      myType(SLVS_C_UNKNOWN),
-      myAttributesList()
+}
+
+SketchSolver_Constraint::~SketchSolver_Constraint()
 {
+  std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
+  for (; anIt1 != myValueMap.end(); anIt1++)
+    myStorage->removeParameter(anIt1->second);
+  myValueMap.clear();
+
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
+  for (; anIt2 != myAttributeMap.end(); anIt2++)
+    myStorage->removeEntity(anIt2->second);
+  myAttributeMap.clear();
+
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anIt3 =  myFeatureMap.begin();
+  for (; anIt3 != myFeatureMap.end(); anIt3++)
+    myStorage->removeEntity(anIt3->second);
+  myFeatureMap.clear();
+
+  std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
+  for (; anIt4 != mySlvsConstraints.end(); anIt4++)
+    myStorage->removeConstraint(*anIt4);
+  mySlvsConstraints.clear();
 }
 
-SketchSolver_Constraint::SketchSolver_Constraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-    : myConstraint(theConstraint),
-      myAttributesList()
+void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
+{
+  myStorage = theStorage;
+  process();
+}
+
+void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
+{
+  myGroup = theGroup;
+  process();
+}
+
+
+void SketchSolver_Constraint::process()
 {
-  myType = getType(myConstraint);
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  int aConstrType = getType();
+  double aValue = 0.0;
+  std::vector<Slvs_hEntity> anAttributes;
+  getAttributes(aValue, anAttributes);
+  if (!myErrorMsg.empty())
+    return;
+
+  Slvs_hGroup aGroupID = myGroup->getId();
+  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+  Slvs_Constraint aConstraint;
+  if (mySlvsConstraints.empty())
+    aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
+        aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+  else {
+    aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
+    aConstraint.valA = aValue;
+    static const int aNbAttrs = 6;
+    Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
+        &aConstraint.ptA, &aConstraint.ptB,
+        &aConstraint.entityA, &aConstraint.entityB,
+        &aConstraint.entityC, &aConstraint.entityD};
+    std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
+    for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
+      *(aConstrAttrs[i]) = *anIter;
+  }
+
+  Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
+  if (mySlvsConstraints.empty())
+    mySlvsConstraints.push_back(anID);
+  else
+    mySlvsConstraints[0] = anID;
+  adjustConstraint();
 }
 
-const int& SketchSolver_Constraint::getType(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
 {
-  myType = SLVS_C_UNKNOWN;
-  if (!theConstraint)
-    return getType();
-
-  DataPtr aConstrData = theConstraint->data();
-  if (!aConstrData || !aConstrData->isValid())
-    return getType();
-
-  // Assign empty names of attributes
-  myAttributesList.clear();
-  for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
-    myAttributesList.push_back(std::string());
-
-  const std::string& aConstraintKind = theConstraint->getKind();
-  // Constraint for coincidence of two points
-  if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
-    int anAttrPos = 0;
-    // Verify the constraint has only two attributes and they are points
-    int aPt2d = 0;  // bit-mapped field, each bit indicates whether the attribute is 2D point
-    int aPt3d = 0;  // bit-mapped field, the same information for 3D points
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (!anAttr)
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint) {
+    if (theConstraint->getKind() != myBaseConstraint->getKind())
+      return;
+    remove(myBaseConstraint);
+    myBaseConstraint = theConstraint;
+    process();
+  }
+
+  // Update all attributes
+  int aType;
+  std::map<Slvs_hEntity, Slvs_hEntity> aRelocationMap;
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
+  for (; aFeatIter != myFeatureMap.end(); aFeatIter++) {
+    Slvs_hEntity aPrevID = aFeatIter->second;
+    aFeatIter->second = changeEntity(aFeatIter->first, aType);
+    if (aFeatIter->second != aPrevID)
+      aRelocationMap[aPrevID] = aFeatIter->second;
+  }
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+    Slvs_hEntity aPrevID = anAttrIter->second;
+    anAttrIter->second = changeEntity(anAttrIter->first, aType);
+    if (anAttrIter->second != aPrevID)
+      aRelocationMap[aPrevID] = anAttrIter->second;
+  }
+
+  // Value if exists
+  DataPtr aData = myBaseConstraint->data();
+  if (!aData) return;
+  AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+    myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
+  double aValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+  // Update constraint
+  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+    Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
+    aConstraint.valA = aValue;
+    Slvs_hEntity* aCoeffs[6] = {
+        &aConstraint.ptA, &aConstraint.ptB,
+        &aConstraint.entityA, &aConstraint.entityB,
+        &aConstraint.entityC, &aConstraint.entityD};
+    for (int i = 0; i < 6; i++) {
+      if (*(aCoeffs[i]) == SLVS_E_UNKNOWN)
         continue;
-      switch (typeOfAttribute(anAttr)) {
-        case POINT2D:  // the attribute is a 2D point
-          aPt2d |= (1 << indAttr);
-          myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        case POINT3D:  // the attribute is a 3D point
-          aPt3d |= (1 << indAttr);
-          myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        default:
-          // Attribute neither 2D nor 3D point is not supported by this type of constraint
-          return getType();
-      }
+      std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFound = aRelocationMap.find(*(aCoeffs[i]));
+      if (aFound != aRelocationMap.end())
+        *(aCoeffs[i]) = aFound->second;
     }
-    // The constrained points should be in first and second positions,
-    // so the expected value of aPt2d or aPt3d is 3
-    if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
-      myType = SLVS_C_POINTS_COINCIDENT;
-    // Constraint parameters are wrong
-    return getType();
+    *aCIter = myStorage->addConstraint(aConstraint);
   }
+  adjustConstraint();
+}
 
-  // Constraint for distance between point and another entity
-  if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
-    int aNbPoints = 0;
-    int aNbEntities = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      switch (typeOfAttribute(anAttr)) {
-        case POINT2D:
-        case POINT3D:
-          myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          break;
-        case LINE:
-          // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
-          myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-          myType = SLVS_C_PT_LINE_DISTANCE;
-          break;
-      }
+bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  if (mySlvsConstraints.empty())
+    return true;
+  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  mySlvsConstraints.clear();
+  return true;
+}
+
+void SketchSolver_Constraint::cleanRemovedEntities()
+{
+  std::set<Slvs_hParam> aRemovedParams;
+  std::set<Slvs_hEntity> aRemovedEntities;
+  std::set<Slvs_hConstraint> aRemovedConstraints;
+  myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
+  while (aFeatIt != myFeatureMap.end()) {
+    if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
+      aFeatIt++;
+      continue;
+    }
+    std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
+    myFeatureMap.erase(aTmpIter);
+  }
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
+  while (anAttrIt != myAttributeMap.end()) {
+    if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
+      anAttrIt++;
+      continue;
+    }
+    std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
+    myAttributeMap.erase(aTmpIter);
+  }
+  std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
+  while (aValIt != myValueMap.end()) {
+    if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
+      aValIt++;
+      continue;
+    }
+    std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
+    myValueMap.erase(aTmpIter);
+  }
+}
+
+void SketchSolver_Constraint::getAttributes(
+    double& theValue,
+    std::vector<Slvs_hEntity>& theAttributes)
+{
+  static const int anInitNbOfAttr = 4;
+  theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+
+  DataPtr aData = myBaseConstraint->data();
+
+  AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+    aData->attribute(SketchPlugin_Constraint::VALUE()));
+  theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+  int aPtInd = 0; // index of first point in the list of attributes
+  int aEntInd = 2; // index of first antity in the list of attributes
+  std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
+  for (; anIter != aConstrAttrs.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (!aRefAttr || !aRefAttr->isInitialized()) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+
+    int aType = SLVS_E_UNKNOWN; // type of created entity
+    Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+    if (anEntity == SLVS_E_UNKNOWN)
+      anEntity = changeEntity(aRefAttr, aType);
+    else {
+      Slvs_Entity anEnt = myStorage->getEntity(anEntity);
+      aType = anEnt.type;
+    }
+
+    if (aType == SLVS_E_UNKNOWN)
+      continue;
+    else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+      theAttributes[aPtInd++] = anEntity; // the point is created
+    else { // another entity (not a point) is created
+      if (aEntInd < anInitNbOfAttr)
+        theAttributes[aEntInd] = anEntity;
+      else
+        theAttributes.push_back(anEntity);
+      aEntInd++;
     }
-    // Verify the correctness of constraint arguments
-    if (aNbPoints == 2 && aNbEntities == 0)
-      myType = SLVS_C_PT_PT_DISTANCE;
-    else if (aNbPoints != 1 || aNbEntities != 1)
-      myType = SLVS_C_UNKNOWN;
-    return getType();
   }
+}
 
-  // Constraint for the given length of a line
-  if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
-    int aNbLines = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
+{
+  // Convert the object of the attribute to the feature
+  FeaturePtr aFeature;
+  if (theAttribute->isObject() && theAttribute->object()) {
+    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+        theAttribute->object());
+    if (!aRC) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return SLVS_E_UNKNOWN;
     }
-    if (aNbLines == 1)
-      myType = SLVS_C_PT_PT_DISTANCE;
-    return getType();
+    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+    aFeature = aDoc->feature(aRC);
+
+    return changeEntity(aFeature, theType);
   }
 
-  // Constraint for two parallel/perpendicular lines
-  bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
-  bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
-  if (isParallel || isPerpendicular) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  return changeEntity(theAttribute->attr(), theType);
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!isInitialized(theEntity))
+    return SLVS_E_UNKNOWN;
+
+  // If the entity is already in the group, try to find it
+  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
+      myAttributeMap.find(theEntity);
+  Slvs_Entity aCurrentEntity;
+  aCurrentEntity.h = SLVS_E_UNKNOWN;
+  if (anEntIter != myAttributeMap.end())
+    aCurrentEntity = myStorage->getEntity(anEntIter->second);
+  else {
+    aResult = myGroup->getAttributeId(theEntity);
+    if (aResult != SLVS_E_UNKNOWN) {
+      Slvs_Entity anEnt = myStorage->getEntity(aResult);
+      theType = anEnt.type;
+      myAttributeMap[theEntity] = aResult;
+      return aResult;
     }
-    if (aNbEntities == 4)
-      myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
-    return getType();
   }
 
-  // Constraint for radius of a circle or an arc of circle
-  if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == CIRCLE || aType == ARC)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  Slvs_hGroup aGroupID = myGroup->getId();
+  // Point in 3D
+  std::shared_ptr<GeomDataAPI_Point> aPoint =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+  if (aPoint) {
+    double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
+    Slvs_hParam aParams[3];
+    for (int i = 0; i < 3; i++) {
+      Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+          myStorage->getParameter(aCurrentEntity.param[i]) :
+          Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+      aPar.val = aXYZ[i];
+      aParams[i] = myStorage->addParameter(aPar);
+    }
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+      aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
+    else { // update entity data
+      for (int i = 0; i < 3; i++)
+        aCurrentEntity.param[i] = aParams[i];
+    }
+    aResult = myStorage->addEntity(aCurrentEntity);
+  } else {
+    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
+    Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+    if (aWorkplaneID == SLVS_E_UNKNOWN)
+      return SLVS_E_UNKNOWN;
+
+    // Point in 2D
+    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+    if (aPoint2D) {
+      double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
+      Slvs_hParam aParams[2];
+      for (int i = 0; i < 2; i++) {
+        Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+            myStorage->getParameter(aCurrentEntity.param[i]) :
+            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+        aPar.val = aXY[i];
+        aParams[i] = myStorage->addParameter(aPar);
+      }
+
+      if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+        aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
+      else { // update entity data
+        for (int i = 0; i < 2; i++)
+          aCurrentEntity.param[i] = aParams[i];
+      }
+      aResult = myStorage->addEntity(aCurrentEntity);
+    } else {
+      // Scalar value (used for the distance entities)
+      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
+      if (aScalar) {
+        Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
+            myStorage->getParameter(aCurrentEntity.param[0]) :
+            Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
+        aParam.val = aScalar->value();
+        Slvs_hParam aValue = myStorage->addParameter(aParam);
+
+        if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+          aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
+        else
+          aCurrentEntity.param[0] = aValue;
+        aResult = myStorage->addEntity(aCurrentEntity);
+      }
     }
-    if (aNbEntities == 3)
-      myType = SLVS_C_DIAMETER;
-    return getType();
   }
 
-  // Constraint for fixed entity
-  if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
-    // Verify that only one entity is filled
-    int aNbAttrs = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType != UNKNOWN)
-        myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  myAttributeMap[theEntity] = aResult;
+  theType = aCurrentEntity.type;
+  return aResult;
+}
+
+Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!theEntity->data() || !theEntity->data()->isValid())
+    return SLVS_E_UNKNOWN;
+  // If the entity is already in the group, try to find it
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
+  Slvs_Entity aCurrentEntity;
+  aCurrentEntity.h = SLVS_E_UNKNOWN;
+  if (anEntIter != myFeatureMap.end())
+    aCurrentEntity = myStorage->getEntity(anEntIter->second);
+  else {
+    aResult = myGroup->getFeatureId(theEntity);
+    if (aResult != SLVS_E_UNKNOWN) {
+      Slvs_Entity anEnt = myStorage->getEntity(aResult);
+      theType = anEnt.type;
+      myFeatureMap[theEntity] = aResult;
+      return aResult;
     }
-    if (aNbAttrs == 1)
-      myType = SLVS_C_WHERE_DRAGGED;
-    return getType();
   }
 
-  // Constraint for horizontal/vertical line
-  bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0);
-  bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0);
-  if (isHorizontal || isVertical) {
-    int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      if (typeOfAttribute(anAttr) == LINE)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  Slvs_hGroup aGroupID = myGroup->getId();
+  Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
+  DataPtr aData = theEntity->data();
+
+  // SketchPlugin features
+  const std::string& aFeatureKind = theEntity->getKind();
+  AttributePtr anAttribute;
+  int anAttrType;
+  // Line
+  if (aFeatureKind == SketchPlugin_Line::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
+      aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
+    else {
+      aCurrentEntity.point[0] = aStart;
+      aCurrentEntity.point[1] = aEnd;
     }
-    if (aNbEntities == 3)
-      myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
-    return getType();
+    aResult = myStorage->addEntity(aCurrentEntity);
   }
+  // Circle
+  else if (aFeatureKind == SketchPlugin_Circle::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
-    static const int aConstrType[3] = {
-        SLVS_C_EQUAL_RADIUS,
-        SLVS_C_EQUAL_LINE_ARC_LEN,
-        SLVS_C_EQUAL_LENGTH_LINES
-    };
-    int aNbLines = 0;
-    int aNbEntities = 2;  // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == LINE) {
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-        aNbLines++;
-      }
-      else if (aType == CIRCLE || aType == ARC)
-        myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+    anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+      aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                        aCenter, aWorkplane.normal, aRadius);
+    } else {
+      aCurrentEntity.point[0] = aCenter;
+      aCurrentEntity.distance = aRadius;
     }
-    if (aNbEntities == 4)
-      myType = aConstrType[aNbLines];
-    return getType();
+    aResult = myStorage->addEntity(aCurrentEntity);
   }
+  // Arc
+  else if (aFeatureKind == SketchPlugin_Arc::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) {
-    static const int anArcPosDefault = 2;
-    static const int aLinePosDefault = 3;
-    int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
-    int aLinePos = aLinePosDefault;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-      AttrType aType = typeOfAttribute(anAttr);
-      if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE)
-        myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      else if (aType == ARC)
-        myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+    anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
+
+    anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
+
+    if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
+      Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
+      aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
+                                            aWorkplane.normal, aCenter, aStart, aEnd);
+    } else {
+      aCurrentEntity.point[0] = aCenter;
+      aCurrentEntity.point[1] = aStart;
+      aCurrentEntity.point[2] = aEnd;
     }
-    if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
-      myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
-    return getType();
+    aResult = myStorage->addEntity(aCurrentEntity);
+  }
+  // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
+  else if (aFeatureKind == SketchPlugin_Point::ID()) {
+    anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
+    if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
+    // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
+    aResult = changeEntity(anAttribute, anAttrType);
+    aCurrentEntity.type = SLVS_E_POINT_IN_3D;
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) {
-    int aNbAttrs = 0;
-    bool hasMirrorLine = false;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
-      if (anAttrRefList) {
-        aNbAttrs++;
-        myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+  if (aResult != SLVS_E_UNKNOWN) {
+    myFeatureMap[theEntity] = aResult;
+    theType = aCurrentEntity.type;
+  }
+  return aResult;
+}
+
+std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
+{
+  std::list<ConstraintPtr> aConstraints;
+  aConstraints.push_back(myBaseConstraint);
+  return aConstraints;
+}
+
+void SketchSolver_Constraint::refresh()
+{
+  cleanErrorMsg();
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
+    std::shared_ptr<GeomDataAPI_Point> aPoint =
+        std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
+    if (aPoint) {
+      Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+      double aXYZ[3];
+      for (int i = 0; i < 3; i++) {
+        Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+        aXYZ[i] = aPar.val;
       }
-      else {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = 
-            aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-        if (typeOfAttribute(anAttr) == LINE) {
-          hasMirrorLine = !hasMirrorLine;
-          myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+      if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
+          fabs(aPoint->y() - aXYZ[1]) > tolerance ||
+          fabs(aPoint->z() - aXYZ[2]) > tolerance)
+        aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
+    } else {
+      // Point in 2D
+      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
+      if (aPoint2D) {
+        Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+        double aXY[2];
+        for (int i = 0; i < 2; i++) {
+          Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
+          aXY[i] = aPar.val;
+        }
+        if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
+            fabs(aPoint2D->y() - aXY[1]) > tolerance)
+        aPoint2D->setValue(aXY[0], aXY[1]);
+      } else {
+        // Scalar value (used for the distance entities)
+        AttributeDoublePtr aScalar =
+            std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+        if (aScalar) {
+          Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
+          Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
+          if (fabs(aScalar->value() - aPar.val) > tolerance)
+            aScalar->setValue(aPar.val);
         }
       }
     }
-    if (aNbAttrs == 2 && hasMirrorLine)
-      myType = SLVS_C_SYMMETRIC_LINE;
-    return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 0) {
-    int aNbAttrs = 0;
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
-      if (anAttrRefList)
-        myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      else {
-        std::shared_ptr<ModelAPI_Attribute> anAttr = 
-            aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
-        AttrType aType = typeOfAttribute(anAttr);
-        if (aType == LINE || aType == ARC)
-          myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
-      }
+  std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
+  for (; aValIter != myValueMap.end(); aValIter++) {
+    AttributeDoublePtr aScalar =
+        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
+    if (aScalar) {
+      Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
+      aScalar->setValue(aPar.val);
     }
-    if (aNbAttrs == 3)
-      myType = SLVS_C_FILLET;
-    return getType();
   }
+}
 
-  /// \todo Implement other kind of constraints
+Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
+{
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
+  if (aFIter == myFeatureMap.end())
+    return SLVS_E_UNKNOWN;
+  return aFIter->second;
+}
+
+Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
+{
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
+  if (anAttrIter == myAttributeMap.end())
+    return SLVS_E_UNKNOWN;
+  return anAttrIter->second;
+}
 
-  return getType();
+bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
+{
+  if (theAttribute->isInitialized())
+    return true;
+  myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+  return false;
 }
 
-// ================= Auxiliary functions ==============================
-AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+
+void SketchSolver_Constraint::calculateMiddlePoint(
+    const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
 {
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(theAttribute);
-  if (!anAttrRef)
-    return UNKNOWN;
+  if (theEntity.type == SLVS_E_LINE_SEGMENT) {
+    double aStartEndXY[2][2];
+    Slvs_Entity aPoint;
+    for (int i = 0; i < 2; i++) {
+      aPoint = myStorage->getEntity(theEntity.point[i]);
+      for (int j = 0; j < 2; j++)
+        aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+    }
+    theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
+    theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
+  } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
+    double anArcPoint[3][2];
+    Slvs_Entity aPoint;
+    for (int i = 0; i < 3; i++) {
+      aPoint = myStorage->getEntity(theEntity.point[i]);
+      for (int j = 0; j < 2; j++)
+        anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
+    }
+    // project last point of arc on the arc
+    double x = anArcPoint[1][0] - anArcPoint[0][0];
+    double y = anArcPoint[1][1] - anArcPoint[0][1];
+    double aRad = sqrt(x*x + y*y);
+    x = anArcPoint[2][0] - anArcPoint[0][0];
+    y = anArcPoint[2][1] - anArcPoint[0][1];
+    double aNorm = sqrt(x*x + y*y);
+    if (aNorm >= tolerance) {
+      anArcPoint[2][0] = x * aRad / aNorm;
+      anArcPoint[2][1] = y * aRad / aNorm;
+    }
+    anArcPoint[1][0] -= anArcPoint[0][0];
+    anArcPoint[1][1] -= anArcPoint[0][1];
+    if (theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[1][0];
+      theY = anArcPoint[0][1] + anArcPoint[1][1];
+      return;
+    } else if (1 - theCoeff < tolerance) {
+      theX = anArcPoint[0][0] + anArcPoint[2][0];
+      theY = anArcPoint[0][1] + anArcPoint[2][1];
+      return;
+    }
 
-  if (anAttrRef->isObject()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        anAttrRef->object());
-    if (!aRC || !aRC->shape())
-      return UNKNOWN;
-
-    if (aRC->shape()->isVertex())
-      return POINT3D;
-    else if (aRC->shape()->isEdge()) {
-      std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
-          aRC->shape());
-      if (anEdge->isLine())
-        return LINE;
-      else if (anEdge->isCircle())
-        return CIRCLE;
-      else if (anEdge->isArc())
-        return ARC;
+    double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad;
+    double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad;
+    if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) {
+      if (anArcPoint[1][0] > 0.0)
+        yEnd = 2.0 - yEnd;
+      else
+        yStart = -2.0 - yStart;
+    } else {
+      if (yStart > yEnd) {
+        yStart = 2.0 - yStart;
+        yEnd = -2.0 - yEnd;
+      } else {
+        yStart = -2.0 - yStart;
+        yEnd = 2.0 - yEnd;
+      }
     }
-  } else {
-    if (anAttrRef->attr().get() != NULL) {
-      const std::string aType = anAttrRef->attr()->attributeType();
-      if (aType == GeomDataAPI_Point2D::typeId())
-        return POINT2D;
-      if (aType == GeomDataAPI_Point2D::typeId())
-        return POINT2D;
+    if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) {
+      if (anArcPoint[1][1] > 0.0)
+        xEnd = 2.0 - xEnd;
+      else
+        xStart = -2.0 - xStart;
+    } else {
+      if (xStart > xEnd) {
+        xStart = 2.0 - xStart;
+        xEnd = -2.0 - xEnd;
+      } else {
+        xStart = -2.0 - xStart;
+        xEnd = 2.0 - xEnd;
+      }
     }
-  }
+    x = (1.0 - theCoeff) * xStart + theCoeff * xEnd;
+    y = (1.0 - theCoeff) * yStart + theCoeff * yEnd;
+    if (x > 1.0) x = 2.0 - x;
+    if (x < -1.0) x = -2.0 - x;
+    if (y > 1.0) y = 2.0 - y;
+    if (y < -1.0) y = -2.0 - y;
 
-  return UNKNOWN;
+    aNorm = sqrt(x*x + y*y);
+    if (aNorm >= tolerance) {
+      x *= aRad / aNorm;
+      y *= aRad / aNorm;
+    } else {
+      x = -0.5 * (anArcPoint[2][1] + anArcPoint[1][1]);
+      y = -0.5 * (anArcPoint[2][0] + anArcPoint[1][0]);
+    }
+    theX = anArcPoint[0][0] + x;
+    theY = anArcPoint[0][1] + y;
+  }
 }
 
index 5a98e31be6f885eb03435a4ba85a71d64ad96c9e..6cfe355f8aa159338b4e2d1b8a3c68a6beeafe92 100644 (file)
 #define SketchSolver_Constraint_H_
 
 #include "SketchSolver.h"
+#include <SketchSolver_Storage.h>
 
 #include <SketchPlugin_Constraint.h>
 
+#include <ModelAPI_AttributeRefAttr.h>
+
 #include <string>
 #include <vector>
 
+class SketchSolver_Group;
+
 /** \class   SketchSolver_Constraint
  *  \ingroup Plugins
- *  \brief   Obtain information about SketchPlugin's constraint
+ *  \brief   Stores mapping between SketchPlugin and SolveSpace constraints data
  */
 class SketchSolver_Constraint
 {
-public:
+protected:
   /// Default constructor
-  SketchSolver_Constraint();
-  /// Creates constraint to manage the given constraint from plugin
-  SketchSolver_Constraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Compute constraint type according to SolveSpace identifiers
-   *         and verify that constraint parameters are correct
-   *  \param[in]  theConstraint constraint which type should be determined
-   *  \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
-   */
-  const int& getType(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /// \brief Returns the type of myConstraint member
-  inline const int& getType() const
-  {
-    return myType;
-  }
+  SketchSolver_Constraint() {}
+  SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+public:
+  virtual ~SketchSolver_Constraint();
+
+  /// \brief Initializes the storage of SolveSpace constraints
+  void setStorage(StoragePtr theStorage);
+  /// \brief Initializes group ID for this constraint
+  void setGroup(SketchSolver_Group* theGroup);
+
+  /// \brief Update constraint
+  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
+  void refresh();
+
+  /// \brief Returns the type of constraint
+  virtual int getType() const = 0;
+
+  /// \brief Checks the constraint is used by current object
+  virtual bool hasConstraint(ConstraintPtr theConstraint) const
+  { return theConstraint == myBaseConstraint; }
+
+  /// \brief Return list of SketchPlugin constraints attached to this object
+  virtual std::list<ConstraintPtr> constraints() const;
+
+  /// \brief Return identifier of SolveSpace entity relating to the feature
+  Slvs_hEntity getId(FeaturePtr theFeature) const;
+  /// \brief Return identifier of SolveSpace entity relating to the attribute
+  Slvs_hEntity getId(AttributePtr theAttribute) const;
+
+  /// \brief Shows error message
+  const std::string& error() const
+  { return myErrorMsg; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+  /// \brief This method is used in derived objects to check consistence of constraint.
+  ///        E.g. the distance between line and point may be signed.
+  virtual void adjustConstraint()
+  {}
+
+  /// \brief Create or change SlveSpace entity according to the given attribute
+  /// \param[in]  theAttribute  reference to the entity to be changed
+  /// \param[out] theType       type of created entity
+  /// \return identifier of created/updated entity
+  Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
+  /// \brief Create or change SlveSpace entity according to the given attribute
+  Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
+  /// \brief Create or change SlveSpace entity according to the given feature
+  Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
+
+  /// \brief Calculate middle point on the specified entity
+  /// \param[in]  theEntity  arc or line
+  /// \param[in]  theCoeff   is a value in [0.0, 1.0] which shows the position of the point on the entity (0.0 - start point, 1.0 - end point)
+  /// \param[out] theX       X coordinate of middle point
+  /// \param[out] theY       Y coordinate of middle point
+  void calculateMiddlePoint(const Slvs_Entity& theEntity, double theCoeff,
+                            double& theX, double& theY) const;
+
+  /// \brief Removes the links to unused entities
+  void cleanRemovedEntities();
+
+  /// \brief Removes last error
+  void cleanErrorMsg()
+  { myErrorMsg.clear(); }
+
+private:
+  /// \brief Sets error, if the attribute is not initialized
+  bool isInitialized(AttributePtr theAttribute);
+
+protected:
+  SketchSolver_Group* myGroup; ///< the group which contains current constraint
+  ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
+  std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
+  std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
+  std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
+  std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
+  StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
+
+  std::string myErrorMsg; ///< error message
+};
+
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
+
+
+
+/** \class   SketchSolver_ConstraintParallel
+ *  \ingroup Plugins
+ *  \brief   Convert Parallel constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
 
-  /// \brief Returns list of attributes names in the correct order required by SolveSpace
-  inline const std::vector<std::string>& getAttributes() const
+  virtual int getType() const
+  { return SLVS_C_PARALLEL; }
+};
+
+
+/** \class   SketchSolver_ConstraintPerpendicular
+ *  \ingroup Plugins
+ *  \brief   Convert Perpendicular constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_PERPENDICULAR; }
+};
+
+
+/** \class   SketchSolver_ConstraintHorizontal
+ *  \ingroup Plugins
+ *  \brief   Convert Horizontal constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_HORIZONTAL; }
+};
+
+
+/** \class   SketchSolver_ConstraintVertical
+ *  \ingroup Plugins
+ *  \brief   Convert Vertical constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_VERTICAL; }
+};
+
+
+/** \class   SketchSolver_ConstraintRadius
+ *  \ingroup Plugins
+ *  \brief   Convert Radius constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintRadius : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintRadius(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_DIAMETER; }
+
+  virtual void adjustConstraint()
   {
-    return myAttributesList;
+    Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
+    aConstraint.valA *= 2.0;
+    myStorage->updateConstraint(aConstraint);
   }
-
- private:
-  std::shared_ptr<SketchPlugin_Constraint> myConstraint;
-  int myType;
-  std::vector<std::string> myAttributesList;
 };
 
 #endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
new file mode 100644 (file)
index 0000000..1172988
--- /dev/null
@@ -0,0 +1,207 @@
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <map>
+
+bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
+{
+  if (myBaseConstraint == theConstraint)
+    return true;
+  std::map<Slvs_hConstraint, ConstraintPtr>::const_iterator anIt = myExtraCoincidence.begin();
+  for (; anIt != myExtraCoincidence.end(); anIt++)
+    if (anIt->second == theConstraint)
+      return true;
+  return false;
+}
+
+std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
+{
+  std::list<ConstraintPtr> aConstraints;
+  aConstraints.push_back(myBaseConstraint);
+  std::map<Slvs_hConstraint, ConstraintPtr>::const_iterator anIt = myExtraCoincidence.begin();
+  for (; anIt != myExtraCoincidence.end(); anIt++)
+    aConstraints.push_back(anIt->second);
+  return aConstraints;
+}
+
+bool SketchSolver_ConstraintCoincidence::isCoincide(
+    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
+{
+  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatIter = myFeatureMap.begin();
+  for (; aFeatIter != myFeatureMap.end(); aFeatIter++)
+    if (theConstraint->myFeatureMap.find(aFeatIter->first) != theConstraint->myFeatureMap.end())
+      return true;
+  std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.begin();
+  for (; anAttrIter != myAttributeMap.end(); anAttrIter++)
+    if (theConstraint->myAttributeMap.find(anAttrIter->first) != theConstraint->myAttributeMap.end())
+      return true;
+  return false;
+}
+
+void SketchSolver_ConstraintCoincidence::attach(
+    std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+{
+  cleanErrorMsg();
+  Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+  // Remove constraints from theConstraint
+  std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
+  for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
+    theConstraint->myStorage->removeConstraint(*aCIter);
+
+  if (myStorage == theConstraint->myStorage) {
+    // Clean removed items
+    std::set<Slvs_hParam> aRemParams;
+    std::set<Slvs_hEntity> aRemEnts;
+    std::set<Slvs_hConstraint> aRemConstr;
+    theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
+  }
+
+  // Copy data.
+  addConstraint(theConstraint->myBaseConstraint);
+  std::map<Slvs_hConstraint, ConstraintPtr>::iterator aConstrIter =
+      theConstraint->myExtraCoincidence.begin();
+  for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
+    addConstraint(aConstrIter->second);
+  // Clear the lists to not remove the entities on destruction
+  theConstraint->mySlvsConstraints.clear();
+  theConstraint->myFeatureMap.clear();
+  theConstraint->myAttributeMap.clear();
+}
+
+Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
+    Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
+{
+  Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
+      SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, 
+      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+  Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
+  mySlvsConstraints.push_back(aNewID);
+  return aNewID;
+}
+
+void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
+{
+  std::list<AttributePtr> anAttrList =
+      theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anIter = anAttrList.begin();
+  std::vector<Slvs_hEntity> anEntities;
+  for (; anIter != anAttrList.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (!aRefAttr || aRefAttr->isObject() ||
+        myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end())
+      continue;
+    int aType;
+    Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr());
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(aRefAttr->attr(), aType);
+    anEntities.push_back(anEntityID);
+  }
+
+  Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
+  Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
+  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++)
+    aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter);
+  myExtraCoincidence[aNewConstr] = theConstraint;
+}
+
+bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (mySlvsConstraints.empty())
+    return true;
+  ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
+  int aPos = -1; // position of constraint in the list (-1 for base constraint)
+  std::map<Slvs_hConstraint, ConstraintPtr>::iterator anExtraIt;
+  if (aConstraint != myBaseConstraint) {
+    anExtraIt = myExtraCoincidence.begin();
+    for (aPos = 0; anExtraIt != myExtraCoincidence.end(); anExtraIt++, aPos++)
+      if (anExtraIt->second == aConstraint)
+        break;
+    if (aPos >= (int)myExtraCoincidence.size())
+      return false; // there is no constraint, which is specified to remove
+    else {
+      bool isEmpty = anExtraIt->first == SLVS_E_UNKNOWN;
+      myExtraCoincidence.erase(anExtraIt);
+      if (isEmpty)
+        return false;
+    }
+  }
+
+  bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
+  mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
+  if (aPos < 0 && !myExtraCoincidence.empty()) {
+    anExtraIt = myExtraCoincidence.begin();
+    // Remove invalid constraints
+    while (anExtraIt != myExtraCoincidence.end()) {
+      if (!anExtraIt->second->data() || !anExtraIt->second->data()->isValid()) {
+        std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+        if (aTempIt->first != SLVS_E_UNKNOWN) {
+          myStorage->removeConstraint(aTempIt->first);
+          std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
+          for (; anIt != mySlvsConstraints.end(); anIt++)
+            if (*anIt == aTempIt->first) {
+              mySlvsConstraints.erase(anIt);
+              break;
+            }
+        }
+        myExtraCoincidence.erase(aTempIt);
+        continue;
+      }
+      anExtraIt++;
+    }
+    // Find first non-extra conststraint
+    while (anExtraIt != myExtraCoincidence.end() && anExtraIt->first == SLVS_E_UNKNOWN)
+      anExtraIt++;
+    if (anExtraIt != myExtraCoincidence.end()) {
+      // Need to specify another base coincidence constraint
+      myBaseConstraint = anExtraIt->second;
+      myExtraCoincidence.erase(anExtraIt);
+      std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+      Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
+      for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
+        Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
+        aConstr.ptA = aBase.ptA;
+        myStorage->updateConstraint(aConstr);
+      }
+    }
+  }
+  // Clear removed attributes
+  std::set<Slvs_hParam> aParamRemoved;
+  std::set<Slvs_hEntity> anEntRemoved;
+  std::set<Slvs_hConstraint> aConstrRemoved;
+  myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
+  std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
+  while (anAttrIter != myAttributeMap.end()) {
+    if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
+      std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
+      myAttributeMap.erase(aTempIt);
+      continue;
+    }
+    anAttrIter++;
+  }
+
+  // Go through remaining extra coincidence and try to add or remove them
+  anExtraIt = myExtraCoincidence.begin();
+  while (anExtraIt != myExtraCoincidence.end()) {
+    if (anExtraIt->first == SLVS_E_UNKNOWN) {
+      if (!anExtraIt->second->data() || !anExtraIt->second->data()->isValid()) {
+        std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+        myExtraCoincidence.erase(aTempIt);
+        continue;
+      }
+      if (mySlvsConstraints.empty()) {
+        myBaseConstraint = anExtraIt->second;
+        std::map<Slvs_hConstraint, ConstraintPtr>::iterator aTempIt = anExtraIt++;
+        myExtraCoincidence.erase(aTempIt);
+        process();
+        continue;
+      } else
+        addConstraint(anExtraIt->second);
+    }
+    anExtraIt++;
+  }
+  return isFullyRemoved;
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h
new file mode 100644 (file)
index 0000000..f726020
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintCoincidence.h
+// Created: 29 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintCoincidence_H_
+#define SketchSolver_ConstraintCoincidence_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+
+/** \class   SketchSolver_ConstraintCoincidence
+ *  \ingroup Plugins
+ *  \brief   Convert coincidence constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_POINTS_COINCIDENT; }
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Checks the constraint is used by current object
+  virtual bool hasConstraint(ConstraintPtr theConstraint) const;
+
+  /// \brief Return list of SketchPlugin constraints attached to this object
+  virtual std::list<ConstraintPtr> constraints() const;
+
+  /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
+  bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
+
+  /// \brief Append all data of coincidence constaint to the current
+  void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
+
+private:
+  /// \brief Creates new coincidence constraint
+  Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
+
+  /// \brief Create full SolveSpace structure according to given constraint
+  void addConstraint(ConstraintPtr theConstraint);
+
+private:
+  std::map<Slvs_hConstraint, ConstraintPtr> myExtraCoincidence; ///< multiple coincidence of points
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp
new file mode 100644 (file)
index 0000000..51f0d73
--- /dev/null
@@ -0,0 +1,87 @@
+#include <SketchSolver_ConstraintDistance.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <GeomAPI_XY.h>
+
+
+void SketchSolver_ConstraintDistance::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntities;
+  getAttributes(aValue, anEntities);
+  if (!myErrorMsg.empty())
+    return;
+
+  // Obtain entities to identify the type of distance
+  static const int aNbPoints = 2;
+  Slvs_hEntity aPoint[aNbPoints] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
+  Slvs_hEntity aLine = SLVS_E_UNKNOWN;
+  myType = SLVS_C_PT_PT_DISTANCE;
+  int aPtPos = 0;
+  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++) {
+    if (*anEntIter == SLVS_E_UNKNOWN)
+      continue;
+    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+    if (anEnt.type == SLVS_E_POINT_IN_2D || anEnt.type == SLVS_E_POINT_IN_3D) {
+      if (aPtPos >= aNbPoints) {
+        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+        return;
+      }
+      aPoint[aPtPos++] = *anEntIter;
+    }
+    else if (anEnt.type == SLVS_E_LINE_SEGMENT) {
+      if (myType == SLVS_C_PT_LINE_DISTANCE) {
+        myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+        return;
+      }
+      aLine = *anEntIter;
+      myType = SLVS_C_PT_LINE_DISTANCE;
+    }
+  }
+
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+      getType(), myGroup->getWorkplaneId(), aValue, aPoint[0], aPoint[1], aLine, SLVS_E_UNKNOWN);
+  aConstraint.h = myStorage->addConstraint(aConstraint);
+  mySlvsConstraints.push_back(aConstraint.h);
+  adjustConstraint();
+}
+
+void SketchSolver_ConstraintDistance::adjustConstraint()
+{
+  if (getType() != SLVS_C_PT_LINE_DISTANCE)
+    return;
+
+  // Get constraint parameters and check the sign of constraint value
+  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+    Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
+    Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA);
+    // Obtain point and line coordinates
+    Slvs_hEntity aPointID[3] = {aConstraint.ptA, aLine.point[0], aLine.point[1]};
+    std::shared_ptr<GeomAPI_XY> aPoints[3];
+    for (int i = 0; i < 3; i++) {
+      Slvs_Entity aPoint = myStorage->getEntity(aPointID[i]);
+      Slvs_Param aParams[2] = {
+          myStorage->getParameter(aPoint.param[0]),
+          myStorage->getParameter(aPoint.param[1])};
+      aPoints[i] = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aParams[0].val, aParams[1].val));
+    }
+    std::shared_ptr<GeomAPI_XY> aLineVec = aPoints[2]->decreased(aPoints[1]);
+    std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoints[0]->decreased(aPoints[1]);
+    if (aPtLineVec->cross(aLineVec) * aConstraint.valA < 0.0) {
+      aConstraint.valA *= -1.0;
+      myStorage->updateConstraint(aConstraint);
+    }
+  }
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.h b/src/SketchSolver/SketchSolver_ConstraintDistance.h
new file mode 100644 (file)
index 0000000..48cadbf
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintDistance.h
+// Created: 31 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintDistance_H_
+#define SketchSolver_ConstraintDistance_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintDistance
+ *  \ingroup Plugins
+ *  \brief   Convert distance constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintDistance : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint), myType(SLVS_C_UNKNOWN)
+  {}
+
+  virtual int getType() const
+  {return myType; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Verifies the sign of the distance between line and point and change it if necessary
+  virtual void adjustConstraint();
+
+private:
+  int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE)
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp
new file mode 100644 (file)
index 0000000..e91ca2c
--- /dev/null
@@ -0,0 +1,70 @@
+#include <SketchSolver_ConstraintEqual.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintEqual::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntities;
+  getAttributes(aValue, anEntities);
+  if (!myErrorMsg.empty())
+    return;
+
+  // Check the quantity of entities of each type
+  int aNbLines = 0;
+  int aNbArcs = 0;
+  int aNbCircs = 0;
+  bool isArcFirst = false; // in line-arc equivalence, the line should be first
+  std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++) {
+    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+    if (anEnt.type == SLVS_E_LINE_SEGMENT)
+      aNbLines++;
+    else if (anEnt.type == SLVS_E_CIRCLE)
+      aNbCircs++;
+    else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
+      aNbArcs++;
+      isArcFirst = (aNbLines == 0);
+    }
+  }
+
+  if (aNbLines + aNbArcs + aNbCircs != 2 ||
+      (aNbLines == aNbCircs && aNbArcs == 0)) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
+
+  switch (aNbLines) {
+  case 0:
+    myType = SLVS_C_EQUAL_RADIUS;
+    break;
+  case 1:
+    myType = SLVS_C_EQUAL_LINE_ARC_LEN;
+    if (isArcFirst) { // change the order of arc and line
+      Slvs_hEntity aTmp = anEntities[2];
+      anEntities[2] = anEntities[3];
+      anEntities[3] = aTmp;
+    }
+    break;
+  default:
+    myType = SLVS_C_EQUAL_LENGTH_LINES;
+    break;
+  }
+
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+      getType(), myGroup->getWorkplaneId(), aValue,
+      anEntities[0], anEntities[1], anEntities[2], anEntities[3]);
+  aConstraint.h = myStorage->addConstraint(aConstraint);
+  mySlvsConstraints.push_back(aConstraint.h);
+  adjustConstraint();
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.h b/src/SketchSolver/SketchSolver_ConstraintEqual.h
new file mode 100644 (file)
index 0000000..c484779
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintEqual.h
+// Created: 1 Apr 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintEqual_H_
+#define SketchSolver_ConstraintEqual_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintEqual
+ *  \ingroup Plugins
+ *  \brief   Convert equality constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintEqual : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintEqual(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return myType; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+private:
+  int myType; ///< type of constraint (applicable: SLVS_C_EQUAL_LENGTH_LINES, SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN)
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.cpp b/src/SketchSolver/SketchSolver_ConstraintFillet.cpp
new file mode 100644 (file)
index 0000000..a8b9bcf
--- /dev/null
@@ -0,0 +1,208 @@
+#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+
+void SketchSolver_ConstraintFillet::getAttributes(
+    double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+{
+  theAttributes.clear();
+
+  DataPtr aData = myBaseConstraint->data();
+  AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+    aData->attribute(SketchPlugin_Constraint::VALUE()));
+  theValue = aValueAttr ? aValueAttr->value() : 0.0;
+
+  std::list<AttributePtr> aBaseAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
+  std::list<AttributePtr>::iterator anIter = aBaseAttrs.begin();
+  for (; anIter != aBaseAttrs.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (!aRefAttr || !aRefAttr->isInitialized()) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+
+    int aType = SLVS_E_UNKNOWN; // type of created entity
+    Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
+    if (anEntity == SLVS_E_UNKNOWN)
+      anEntity = changeEntity(aRefAttr, aType);
+
+    if (aType == SLVS_E_UNKNOWN)
+      continue;
+    theAttributes.push_back(anEntity);
+  }
+
+  // Fillet objects
+  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+    aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
+  if (!aFilletRefList || !aFilletRefList->isInitialized()) {
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+    return;
+  }
+  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
+  if (aFilletList.size() < theAttributes.size() + 1) {
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+    return;
+  }
+  FeaturePtr aFilletFeature;
+  ResultConstructionPtr aRC;
+  int aType;
+  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
+  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
+    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
+    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
+        std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
+    if (!aFilletFeature) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+    Slvs_hEntity anEntity = changeEntity(aFilletFeature, aType);
+    theAttributes.push_back(anEntity);
+  }
+}
+
+void SketchSolver_ConstraintFillet::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntID;
+  getAttributes(aValue, anEntID);
+  if (!myErrorMsg.empty())
+    return;
+
+  // Obtain the entities itself:
+  // First two are base entities
+  // Second two are trimmed them
+  // Last one is a fillet arc
+  std::vector<Slvs_Entity> anEntities;
+  std::vector<Slvs_hEntity>::iterator anIt = anEntID.begin();
+  for (; anIt != anEntID.end(); anIt++)
+    anEntities.push_back(myStorage->getEntity(*anIt));
+
+  // Check the base entities have a coincident point
+  Slvs_hEntity aPointsToFind[4];
+  for (int i = 0; i < 2; i++) {
+    int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+    aPointsToFind[2*i]  = anEntities[i].point[aShift];
+    aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
+  }
+  // Search coincident points
+  int aCoincInd[2]; // indices of coincident points on each entity (0 - first, 1 - last)
+  bool isPointFound = false;
+  for (int i = 0; i < 2 && !isPointFound; i++)
+    for (int j = 2; j < 4 && !isPointFound; j++)
+      if (myStorage->isCoincident(aPointsToFind[i], aPointsToFind[j])) {
+        aCoincInd[0] = i;
+        aCoincInd[1] = j - 2;
+        isPointFound = true;
+      }
+  if (!isPointFound) {
+    // There is no coincident points between tangential objects. Generate error message
+    myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+    return;
+  }
+
+  // For correct result, move floating points of fillet on the middle points of base objects
+  Slvs_Entity aPoint;
+  Slvs_Param aParam;
+  double anArcPoints[3][2];
+  for (int i = 0; i < 2; i++) {
+    calculateMiddlePoint(anEntities[i], 0.1 + 0.8 * aCoincInd[i], anArcPoints[i+1][0], anArcPoints[i+1][1]);
+    aPoint = myStorage->getEntity(anEntities[i+2].point[aCoincInd[i]]);
+    for (int j = 0; j < 2; j++) {
+      aParam = myStorage->getParameter(aPoint.param[j]);
+      aParam.val = anArcPoints[i+1][j];
+      aPoint.param[j] = myStorage->updateParameter(aParam);
+    }
+  }
+  anArcPoints[0][0] = 0.5 * (anArcPoints[1][0] + anArcPoints[2][0]);
+  anArcPoints[0][1] = 0.5 * (anArcPoints[1][1] + anArcPoints[2][1]);
+  // Check the arc is need to be reversed
+  double aSharedPoint[2];
+  aPoint = myStorage->getEntity(aPointsToFind[aCoincInd[0]]);
+  for (int j = 0; j < 2; j++)
+    aSharedPoint[j] = myStorage->getParameter(aPoint.param[j]).val;
+  double aCross = (anArcPoints[1][0] - anArcPoints[0][0]) * (aSharedPoint[1] - anArcPoints[0][1]) -
+                  (anArcPoints[1][1] - anArcPoints[0][1]) * (aSharedPoint[0] - anArcPoints[0][0]);
+  if (aCross < 0.0) { // reverse fillet arc
+    double aTmp;
+    for (int j = 0; j < 2; j++) {
+      aTmp = anArcPoints[1][j];
+      anArcPoints[1][j] = anArcPoints[2][j];
+      anArcPoints[2][j] = aTmp;
+    }
+  }
+  // update fillet arc coordinates
+  for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
+    aPoint = myStorage->getEntity(anEntities.back().point[indArcPt]);
+    for (int j = 0; j < 2; j++) {
+      aParam = myStorage->getParameter(aPoint.param[j]);
+      aParam.val = anArcPoints[indArcPt][j];
+      aPoint.param[j] = myStorage->updateParameter(aParam);
+    }
+  }
+
+  for (int indEnt = 0; indEnt < 2; indEnt++) {
+    int aShift = anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+    // one point of fillet object should be coincident with the point on base, non-coincident with another base object
+    Slvs_hEntity aBaseID = anEntities[indEnt].point[1 - aCoincInd[indEnt] + aShift];
+    Slvs_hEntity aFilletID = anEntities[2 + indEnt].point[1 - aCoincInd[indEnt] + aShift];
+    Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
+        SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
+        0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    aCoincConstr.h = myStorage->addConstraint(aCoincConstr);
+    mySlvsConstraints.push_back(aCoincConstr.h);
+
+    // another point of fillet object should be placed on the base object
+    Slvs_Constraint aPonCurveConstr;
+    if (anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE) {
+      // centers of arcs should be coincident
+      aBaseID = anEntities[indEnt].point[0];
+      aFilletID = anEntities[2 + indEnt].point[0];
+      aPonCurveConstr = Slvs_MakeConstraint(
+          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
+          0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    } else {
+      aFilletID = anEntities[2 + indEnt].point[aCoincInd[indEnt]];
+      aPonCurveConstr = Slvs_MakeConstraint(
+          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(),
+          0.0, aFilletID, SLVS_E_UNKNOWN, anEntities[indEnt].h, SLVS_E_UNKNOWN);
+    }
+    aPonCurveConstr.h = myStorage->addConstraint(aPonCurveConstr);
+    mySlvsConstraints.push_back(aPonCurveConstr.h);
+  }
+}
+
+bool SketchSolver_ConstraintFillet::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  bool isFullyRemoved = true;
+  std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++)
+   isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+  mySlvsConstraints.clear();
+
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  return true;
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.h b/src/SketchSolver/SketchSolver_ConstraintFillet.h
new file mode 100644 (file)
index 0000000..126d46d
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintFillet.h
+// Created: 1 Apr 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintFillet_H_
+#define SketchSolver_ConstraintFillet_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintFillet
+ *  \ingroup Plugins
+ *  \brief   Convert fillet constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintFillet : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintFillet(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_FILLET; }
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  ///
+  /// Parameter theAttributes contains 5 elements:
+  /// Two first entities in theAttributes list correspond to base features of fillet,
+  /// the next two entities represent trimmed base features and the last one is a fillet arc.
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp
deleted file mode 100644 (file)
index 6462775..0000000
+++ /dev/null
@@ -1,2349 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintGroup.cpp
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintGroup.h"
-
-#include <SketchSolver_Constraint.h>
-
-#include <Events_Error.h>
-#include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Document.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintLength.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintRigid.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <math.h>
-#include <assert.h>
-
-/// Tolerance for value of parameters
-const double tolerance = 1.e-10;
-
-/**
- * Collects all sketch solver error' codes
- * as inline static functions
- */
- // TODO: Move this class into a separate file
-class SketchSolver_Error
-{
- public:
-  /// The value parameter for the constraint
-  inline static const std::string& CONSTRAINTS()
-  {
-    static const std::string MY_ERROR_VALUE("Conflicting constraints");
-    return MY_ERROR_VALUE;
-  }
-  /// The entities need to have shared point, but they have not
-  inline static const std::string& NO_COINCIDENT_POINTS()
-  {
-    static const std::string MY_ERROR_VALUE("Objects should have coincident point");
-    return MY_ERROR_VALUE;
-  }
-};
-
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
-
-/** \brief Search the entity/parameter with specified ID in the list of elements
- *  \param[in] theEntityID unique ID of the element
- *  \param[in] theEntities list of elements
- *  \return position of the found element or -1 if the element is not found
- */
-template<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
-
-// ========================================================
-// =========  SketchSolver_ConstraintGroup  ===============
-// ========================================================
-
-SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup(
-    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
-    : myID(++myGroupIndexer),
-      myParamMaxID(0),
-      myEntityMaxID(0),
-      myConstrMaxID(0),
-      myConstraintMap(),
-      myNeedToSolve(false),
-      myConstrSolver()
-{
-  myParams.clear();
-  myEntities.clear();
-  myEntOfConstr.clear();
-  myConstraints.clear();
-
-  myTempConstraints.clear();
-  myTempPointWhereDragged.clear();
-  myTempPointWDrgdID = 0;
-
-  // Initialize workplane
-  myWorkplane.h = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
-  assert(addWorkplane(theWorkplane));
-#else
-  addWorkplane(theWorkplane);
-#endif
-}
-
-SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
-  myParams.clear();
-  myEntities.clear();
-  myEntOfConstr.clear();
-  myConstraints.clear();
-  myConstraintMap.clear();
-  myTempConstraints.clear();
-  myTempPointWhereDragged.clear();
-
-  // If the group with maximal identifier is deleted, decrease the indexer
-  if (myID == myGroupIndexer)
-    myGroupIndexer--;
-}
-
-// ============================================================================
-//  Function: isBaseWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verify the group is based on the given workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isBaseWorkplane(
-    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const
-{
-  return theWorkplane == mySketch;
-}
-
-// ============================================================================
-//  Function: isInteract
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verify are there any entities in the group used by given constraint
-// ============================================================================
-bool SketchSolver_ConstraintGroup::isInteract(
-    std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
-  // Check the group is empty
-  if (isEmpty())
-    return true;
-
-  // Check if the feature is already in the group
-  if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end())
-    return true;
-  std::shared_ptr<SketchPlugin_Constraint> aConstr =
-      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
-  if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end())
-    return true;
-
-  // Go through the attributes and verify if some of them already in the group
-  std::list<std::shared_ptr<ModelAPI_Attribute>> 
-      anAttrList = theFeature->data()->attributes(std::string());
-  std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
-      anAttrIter = anAttrList.begin();
-  for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
-    AttributeRefListPtr aCAttrRefList = 
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
-    if (aCAttrRefList) {
-      std::list<ObjectPtr> anObjList = aCAttrRefList->list();
-      std::list<ObjectPtr>::iterator anIt = anObjList.begin();
-      for ( ; anIt != anObjList.end(); anIt++) {
-        FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
-        if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
-          return true;
-      }
-      continue;
-    }
-    AttributeRefAttrPtr aCAttrRef =
-        std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
-    if (!aCAttrRef || !aCAttrRef->isObject()) {
-      std::shared_ptr<ModelAPI_Attribute> anAttr = 
-          aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
-      if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
-        return true;
-    } else {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aCAttrRef->object());
-      if (!aRC)
-        continue;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      FeaturePtr aFeature = aDoc->feature(aRC);
-      if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
-        return true;
-      // search attributes of a feature to be parameters of constraint
-      std::list<std::shared_ptr<ModelAPI_Attribute> > aFeatAttrList =
-          aFeature->data()->attributes(std::string());
-      std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aFAIter = aFeatAttrList
-          .begin();
-      for (; aFAIter != aFeatAttrList.end(); aFAIter++)
-        if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end())
-          return true;
-    }
-  }
-
-  // Entities did not found
-  return false;
-}
-
-// ============================================================================
-//  Function: checkConstraintConsistence
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  verifies and changes parameters of the constraint
-// ============================================================================
-void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint)
-{
-  if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) {
-    // Get constraint parameters and check the sign of constraint value
-
-    // point coordinates
-    int aPtPos = Search(theConstraint.ptA, myEntities);
-    int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aPoint(
-        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
-    // line coordinates
-    int aLnPos = Search(theConstraint.entityA, myEntities);
-    aPtPos = Search(myEntities[aLnPos].point[0], myEntities);
-    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aStart(
-        new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val));
-    aPtPos = Search(myEntities[aLnPos].point[1], myEntities);
-    aPtParamPos = Search(myEntities[aPtPos].param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aEnd(
-        new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val));
-
-    aEnd = aEnd->added(aStart);
-    aPoint = aPoint->added(aStart);
-    if (aPoint->cross(aEnd) * theConstraint.valA < 0.0)
-      theConstraint.valA *= -1.0;
-  }
-}
-
-// ============================================================================
-//  Function: changeConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  // There is no workplane yet, something wrong
-  if (myWorkplane.h == SLVS_E_UNKNOWN)
-    return false;
-
-  if (theConstraint) {
-    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
-      return changeRigidConstraint(theConstraint);
-    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
-      return changeMirrorConstraint(theConstraint);
-    if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID())
-      return changeFilletConstraint(theConstraint);
-  }
-
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  // Create constraint parameters
-  double aDistance = 0.0;  // scalar value of the constraint
-  AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-      theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE()));
-  if (aDistAttr) {
-    aDistance = aDistAttr->value();
-    // Issue #196: checking the positivity of the distance constraint
-    if (aDistance < tolerance &&
-       (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE))
-      return false;
-    // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
-    if (aConstrType == SLVS_C_DIAMETER)
-      aDistance *= 2.0;
-    if (aConstrMapIter != myConstraintMap.end()
-        && fabs(aConstrIter->valA - aDistance) > tolerance) {
-      myNeedToSolve = true;
-      aConstrIter->valA = aDistance;
-    }
-  }
-
-  size_t aNbTmpConstraints = myTempConstraints.size();
-  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE];  // parameters of the constraint
-  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-    aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
-    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-        ModelAPI_AttributeRefAttr>(
-        theConstraint->data()->attribute(aConstraintAttributes[indAttr]));
-    if (!aConstrAttr)
-      continue;
-
-    // Convert the object of the attribute to the feature
-    FeaturePtr aFeature;
-    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aConstrAttr->object());
-      if (!aRC)
-        continue;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      aFeature = aDoc->feature(aRC);
-    }
-
-    // For the length constraint the start and end points of the line should be added to the entities list instead of line
-    if (aConstrType == SLVS_C_PT_PT_DISTANCE
-        && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) {
-      Slvs_hEntity aLineEnt = changeEntityFeature(aFeature);
-      int aEntPos = Search(aLineEnt, myEntities);
-      aConstrEnt[indAttr++] = myEntities[aEntPos].point[0];
-      aConstrEnt[indAttr++] = myEntities[aEntPos].point[1];
-      while (indAttr < CONSTRAINT_ATTR_SIZE)
-        aConstrEnt[indAttr++] = 0;
-      break;  // there should be no other entities
-    } else if (aConstrAttr->isObject())
-      aConstrEnt[indAttr] = changeEntityFeature(aFeature);
-    else
-      aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
-  }
-
-  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-    // Several points may be coincident, it is not necessary to store all constraints between them.
-    // Try to find sequence of coincident points which connects the points of new constraint
-    if (aConstrType == SLVS_C_POINTS_COINCIDENT) {
-      if (aConstrEnt[0] == aConstrEnt[1])  // no need to add self coincidence
-        return false;
-      if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) {
-        myExtraCoincidence.insert(theConstraint);  // the constraint is stored for further purposes
-        return false;
-      }
-      if (aNbTmpConstraints < myTempConstraints.size()) {
-        // There was added temporary constraint. Check that there is no coincident points which already rigid.
-
-        // Get list of already fixed points
-        std::set<Slvs_hEntity> anAlreadyFixed;
-        std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-        for (; aCIter != myConstraints.end(); aCIter++)
-          if (aCIter->type == SLVS_C_WHERE_DRAGGED) {
-            std::list<Slvs_hConstraint>::const_iterator aTmpIt = myTempConstraints.begin();
-            for (; aTmpIt != myTempConstraints.end(); aTmpIt++)
-              if (*aTmpIt == aCIter->h)
-                break;
-            if (aTmpIt == myTempConstraints.end())
-              anAlreadyFixed.insert(aCIter->ptA);
-          }
-
-        std::set<Slvs_hConstraint> aTmpConstrToDelete;
-        std::list<Slvs_hConstraint>::reverse_iterator aTmpIter = myTempConstraints.rbegin();
-        size_t aCurSize = myTempConstraints.size();
-        for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend();
-            aTmpIter++, aCurSize--) {
-          int aConstrPos = Search(*aTmpIter, myConstraints);
-          std::vector<std::set<Slvs_hEntity> >::const_iterator
-            aCoincIter = myCoincidentPoints.begin();
-          for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-            if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) {
-              std::set<Slvs_hEntity>::const_iterator anIt;
-              for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++)
-                if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) {
-                  aTmpConstrToDelete.insert(*aTmpIter);
-                  break;
-                }
-              break;
-            }
-        }
-        if (!aTmpConstrToDelete.empty())
-          removeTemporaryConstraints(aTmpConstrToDelete);
-      }
-    }
-    // For the tangency constraints it is necessary to identify which points of entities are coincident
-    int aSlvsOtherFlag = 0;
-    int aSlvsOther2Flag = 0;
-    if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) {
-      // Search entities used by constraint
-      int anEnt1Pos = Search(aConstrEnt[2], myEntities);
-      int anEnt2Pos = Search(aConstrEnt[3], myEntities);
-      // Obtain start and end points of entities
-      Slvs_hEntity aPointsToFind[4];
-      aPointsToFind[0] = myEntities[anEnt1Pos].point[1];
-      aPointsToFind[1]= myEntities[anEnt1Pos].point[2];
-      bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT);
-      aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1];
-      aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2];
-      // Search coincident points
-      bool isPointFound[4];
-      std::vector<std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
-      for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) {
-        for (int i = 0; i < 4; i++)
-          isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end());
-        if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) {
-          // the arc is tangent by end point
-          if (isPointFound[1]) aSlvsOtherFlag = 1;
-          // the second item is an arc and it is tangent by end point too
-          if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1;
-          break;
-        }
-      }
-      if (aCPIter == myCoincidentPoints.end()) {
-        // There is no coincident points between tangential objects. Generate error message
-        Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-        return false;
-      }
-    }
-
-    // Create SolveSpace constraint structure
-    Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
-                                                      myWorkplane.h, aDistance, aConstrEnt[0],
-                                                      aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
-    if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag;
-    if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag;
-    myConstraints.push_back(aSlvsConstr);
-    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aSlvsConstr.h);
-    int aConstrPos = Search(aSlvsConstr.h, myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-    myNeedToSolve = true;
-  } else { // Attributes of constraint may be changed => update constraint
-    Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB,
-                                   &aConstrIter->entityA, &aConstrIter->entityB,
-                                   &aConstrIter->entityC, &aConstrIter->entityD};
-    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
-      if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr])
-      {
-        *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr];
-        myNeedToSolve = true;
-      }
-    }
-  }
-
-  // Update flags of entities to be used by constraints
-  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
-    if (aConstrEnt[indAttr] != 0) {
-      int aPos = Search(aConstrEnt[indAttr], myEntities);
-      myEntOfConstr[aPos] = true;
-      // Sub-entities should be used implcitly
-      Slvs_hEntity* aEntPtr = myEntities[aPos].point;
-      while (*aEntPtr != 0) {
-        aPos = Search(*aEntPtr, myEntities);
-        myEntOfConstr[aPos] = true;
-        aEntPtr++;
-      }
-    }
-
-  checkConstraintConsistence(*aConstrIter);
-  return true;
-}
-
-// ============================================================================
-//  Function: changeRigidConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Rigid" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeRigidConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN;
-  std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(
-      theConstraint->data()->attribute(aConstraintAttributes[0]));
-  if (!aConstrAttr)
-    return false;
-
-  // Convert the object of the attribute to the feature
-  FeaturePtr aFeature;
-  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        aConstrAttr->object());
-    if (!aRC)
-      return false;
-    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-    aFeature = aDoc->feature(aRC);
-  }
-
-  aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr());
-
-  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
-    // Check the fixed entity is not a point.
-    std::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = std::dynamic_pointer_cast<
-        ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0]));
-    std::shared_ptr<GeomDataAPI_Point> aPoint =
-        std::dynamic_pointer_cast<GeomDataAPI_Point>(aConstrAttr->attr());
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aConstrAttr->attr());
-    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,
-          aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-      myConstraints.push_back(aConstraint);
-      myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>(1, aConstraint.h);
-      int aConstrPos = Search(aConstraint.h, myConstraints);
-      aConstrIter = myConstraints.begin() + aConstrPos;
-      myNeedToSolve = true;
-    } else {
-      myConstraintMap[theConstraint] = std::vector<Slvs_hConstraint>();
-
-      // To avoid SolveSpace problems:
-      // * if the circle is rigid, we will fix its center and radius;
-      // * if the arc is rigid, we will fix its start and end points and radius.
-      double aRadius = 0.0;
-      bool isArc = false;
-      bool isCircle = false;
-      if (aFeature) {
-        if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
-          std::shared_ptr<GeomDataAPI_Point2D> aCenter =
-              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-              aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-          std::shared_ptr<GeomDataAPI_Point2D> aStart =
-              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-              aFeature->data()->attribute(SketchPlugin_Arc::START_ID()));
-          aRadius = aStart->pnt()->distance(aCenter->pnt());
-          isArc = true;
-        } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
-          aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
-              aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
-          isCircle = true;
-        }
-      }
-
-      // Get list of already fixed points
-      std::set<Slvs_hEntity> anAlreadyFixed;
-      std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
-      for (; aCIter != myConstraints.end(); aCIter++)
-        if (aCIter->type == SLVS_C_WHERE_DRAGGED)
-          anAlreadyFixed.insert(aCIter->ptA);
-
-      // Create constraints to fix the parameters of the entity
-      int aEntPos = Search(aConstrEnt, myEntities);
-      Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point;
-      if (isArc) aPointsPtr++; // avoid to fix center of arc
-      while (*aPointsPtr != 0) {
-        // Avoid to create additional "Rigid" constraints for coincident points
-        bool isCoincAlreadyFixed = false;
-        if (!anAlreadyFixed.empty()) {
-          if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end())
-            isCoincAlreadyFixed = true;
-
-          std::vector<std::set<Slvs_hEntity> >::const_iterator aCoincIter =
-              myCoincidentPoints.begin();
-          for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) {
-            if (aCoincIter->find(*aPointsPtr) == aCoincIter->end())
-              continue;
-            std::set<Slvs_hEntity>::const_iterator anIter = anAlreadyFixed.begin();
-            for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++)
-              if (aCoincIter->find(*anIter) != aCoincIter->end())
-                isCoincAlreadyFixed = true;
-          }
-        }
-
-        if (!isCoincAlreadyFixed) {
-          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
-              *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
-          myConstraints.push_back(aConstraint);
-          myConstraintMap[theConstraint].push_back(aConstraint.h);
-        }
-        aPointsPtr++;
-      }
-
-      if (isArc || isCircle) { // add radius constraint
-        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius,
-            SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN);
-        myConstraints.push_back(aConstraint);
-        myConstraintMap[theConstraint].push_back(aConstraint.h);
-      }
-
-      // The object is already rigid, so there is no constraints added
-      if (myConstraintMap[theConstraint].empty()) {
-        myConstraintMap.erase(theConstraint);
-        myNeedToSolve = false;
-      }
-      else
-        myNeedToSolve = true;
-    }
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeMirrorConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Mirror" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  DataPtr aConstrData = theConstraint->data();
-
-  // 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
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN
-      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
-  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-      aConstrData->attribute(aConstraintAttributes[0]));
-  if (!aConstrAttr)
-    return false;
-
-  // Convert the object of the attribute to the feature
-  FeaturePtr aMirrorLineFeat;
-  if (aConstrAttr->isObject() && aConstrAttr->object()) {
-    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-        aConstrAttr->object());
-    if (!aRC)
-      return false;
-    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-    aMirrorLineFeat = aDoc->feature(aRC);
-  }
-  aMirrorLineEnt = aConstrAttr->isObject() ?
-      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
-
-  // 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();
-  // remove all empty items
-  std::list<ObjectPtr>::iterator anIt = aBaseList.begin();
-  std::list<ObjectPtr>::iterator aTmpIt;
-  while (anIt != aBaseList.end()) {
-    aTmpIt = anIt;
-    anIt++;
-    if (!(*aTmpIt))
-      aBaseList.erase(aTmpIt);
-  }
-  anIt = aMirroredList.begin();
-  while (anIt != aMirroredList.end()) {
-    aTmpIt = anIt;
-    anIt++;
-    if (!(*aTmpIt))
-      aMirroredList.erase(aTmpIt);
-  }
-  if (aBaseList.empty() || aBaseList.size() != aMirroredList.size())
-    return false;
-
-  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]);
-    }
-  }
-
-  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<ModelAPI_Feature>(*aBaseIter);
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
-    aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_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);
-          myEntOfConstr.push_back(true);
-          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);
-          aNewConstraints.push_back(aPonCircConstr.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);
-    // 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++) {
-      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
-      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
-          std::dynamic_pointer_cast<ModelAPI_Feature>(*aBaseIter);
-      if (!aBaseFeature) continue;
-      std::list<AttributePtr> aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
-      if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) {
-        std::list<AttributePtr>::iterator anIt = aPoints.begin();
-        for ( ; anIt != aPoints.end(); anIt++) {
-          addTemporaryConstraintWhereDragged(*anIt);
-        }
-      } else {
-        // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace)
-        AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID());
-        std::map<AttributePtr, Slvs_hEntity>::iterator aFound = myEntityAttrMap.find(aCenterAttr);
-        Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0};
-        AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID());
-        aFound = myEntityAttrMap.find(aStartAttr);
-        anArcPoints[1] = aFound->second;
-        AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID());
-        aFound = myEntityAttrMap.find(aEndAttr);
-        anArcPoints[2] = aFound->second;
-
-        bool isFixed[3] = {false, false, false};
-        int aNbFixed = 0; // number of already fixed points on the arc
-        for (int i = 0; i < 3; i++) {
-          std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-          for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) {
-            if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end())
-              continue;  // the entity was not found in current set
-
-            // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
-            std::vector<Slvs_Constraint>::iterator aConstrIter = myConstraints.begin();
-            for (; aConstrIter != myConstraints.end(); aConstrIter++)
-              if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && 
-                  aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) {
-                isFixed[i] = true;
-                aNbFixed++;
-                break;  // the SLVS_C_WHERE_DRAGGED constraint already exists
-              }
-          }
-        }
-        if (aNbFixed < 2) { // append constraints
-          if (!isFixed[0])
-            addTemporaryConstraintWhereDragged(aCenterAttr);
-          if (!isFixed[1] && (isFixed[0] || aNbFixed == 0))
-            addTemporaryConstraintWhereDragged(aStartAttr);
-        }
-      }
-    }
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeFilletConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the "Fillet" constraint in the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::changeFilletConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  DataPtr aConstrData = theConstraint->data();
-
-  // Search this constraint in the current group to update it
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
-  std::vector<Slvs_Constraint>::iterator aConstrIter;
-  if (aConstrMapIter != myConstraintMap.end()) {
-    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
-    aConstrIter = myConstraints.begin() + aConstrPos;
-  }
-
-  // Get constraint type and verify the constraint parameters are correct
-  SketchSolver_Constraint aConstraint(theConstraint);
-  int aConstrType = aConstraint.getType();
-  if (aConstrType == SLVS_C_UNKNOWN)
-    return false;
-  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
-
-  // Obtain hEntity for basic objects of fillet
-  Slvs_hEntity aBaseObject[2];
-  FeaturePtr aBaseFeature[2];
-  for (unsigned int indAttr = 0; indAttr < 2; indAttr++) {
-    AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        aConstrData->attribute(aConstraintAttributes[indAttr]));
-    if (!aConstrAttr)
-      return false;
-    if (aConstrAttr->isObject() && aConstrAttr->object()) {
-      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
-          aConstrAttr->object());
-      if (!aRC)
-        return false;
-      std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
-      aBaseFeature[indAttr] = aDoc->feature(aRC);
-    }
-    aBaseObject[indAttr] = aConstrAttr->isObject() ?
-        changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr());
-  }
-  // Check the base entities have a coincident point
-  int aBaseObjInd[2] = {
-      Search(aBaseObject[0], myEntities),
-      Search(aBaseObject[1], myEntities)
-    };
-  int aShift[2] = { // shift for calculating correct start and end points for different types of objects
-      myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-      myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0,
-    };
-  Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object
-      myEntities[aBaseObjInd[0]].point[aShift[0]],
-      myEntities[aBaseObjInd[0]].point[1+aShift[0]]
-    };
-  Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object
-      myEntities[aBaseObjInd[1]].point[aShift[1]],
-      myEntities[aBaseObjInd[1]].point[1+aShift[1]]
-    };
-  bool isCoincidentFound = false;
-  int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points
-  std::vector<std::set<Slvs_hEntity> >::iterator aCPIter = myCoincidentPoints.begin();
-  for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++)
-    for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++)
-      for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++)
-        if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() &&
-            aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) {
-          aBaseCoincInd[0] = ind1;
-          aBaseCoincInd[1] = ind2;
-          isCoincidentFound = true;
-        }
-  if (!isCoincidentFound) {
-    // There is no coincident points between objects. Generate error message
-    Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this);
-    return false;
-  }
-
-  // Create fillet entities
-  // - first object is placed on the first base 
-  // - second object is on the second base 
-  // - third object is a filleting arc
-  static const int aNbFilletEnt = 3;
-  Slvs_hEntity aFilletEnt[aNbFilletEnt];
-  int aFilletObjInd[aNbFilletEnt];
-  AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-      aConstrData->attribute(aConstraintAttributes[2]));
-  if (!aFilletRefList)
-    return false;
-  std::list<ObjectPtr> aFilletList = aFilletRefList->list();
-  if (aFilletList.size() < aNbFilletEnt)
-    return false;
-  FeaturePtr aFilletFeature;
-  ResultConstructionPtr aRC;
-  std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
-  for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
-    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
-    aFilletFeature = aRC ? aRC->document()->feature(aRC) :
-        std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
-    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
-  if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) {
-    double anArcPoints[6];
-    for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) {
-      int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
-      int aPointsPos[2] = {
-          Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities),
-          Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities)
-        };
-      int aParamPos[2] = {
-          Search(myEntities[aPointsPos[0]].param[0], myParams),
-          Search(myEntities[aPointsPos[1]].param[0], myParams)
-        };
-      int anIndex = aParamPos[aBaseCoincInd[indEnt]];
-      if (anIndShift == 0) {
-        myParams[anIndex].val =
-            0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val);
-        myParams[1 + anIndex].val =
-            0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val);
-      } else { // place the changed point on the arc
-        double x = 0, y = 0;
-        calculateMiddlePoint(aFilletEnt[indEnt], x, y);
-        myParams[anIndex].val = x;
-        myParams[1 + anIndex].val = y;
-      }
-      anArcPoints[indEnt*2+2] = myParams[anIndex].val;
-      anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val;
-    }
-    anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]);
-    anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]);
-    for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
-      int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities);
-      int aParamPos = Search(myEntities[aPtPos].param[0], myParams);
-      myParams[aParamPos].val = anArcPoints[indArcPt * 2];
-      myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1];
-    }
-  }
-
-  // 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
-    aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes
-    Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd];
-    Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-    if (isExists) {
-      myConstraints[aCurConstrPos].ptA = aPtBase;
-      myConstraints[aCurConstrPos].ptB = aPtFillet;
-      aCMapIter++;
-      aCurConstrPos = Search(*aCMapIter, myConstraints);
-    } 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);
-      myConstraints.push_back(aCoincConstr);
-      aConstrList.push_back(aCoincConstr.h);
-    }
-
-    // another point of fillet object should be placed on the base object
-    Slvs_Constraint aPonCurveConstr;
-    int aTangentType;
-    if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) {
-      // centers of arcs should be coincident
-      aPtBase = myEntities[aBaseObjInd[indEnt]].point[0];
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0];
-      if (isExists) {
-        myConstraints[aCurConstrPos].ptA = aPtBase;
-        myConstraints[aCurConstrPos].ptB = aPtFillet;
-        aCMapIter++;
-        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);
-      }
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below
-      aTangentType = SLVS_C_CURVE_CURVE_TANGENT;
-    } else {
-      aPtInd = aBaseCoincInd[indEnt];
-      aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd];
-      if (isExists) {
-        myConstraints[aCurConstrPos].ptA = aPtFillet;
-        aCMapIter++;
-        if (aCMapIter != aCMapEnd)
-          aCurConstrPos = Search(*aCMapIter, myConstraints);
-      } else {
-        aPonCurveConstr = Slvs_MakeConstraint(
-            ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h,
-            0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN);
-      }
-      aTangentType = SLVS_C_ARC_LINE_TANGENT;
-    }
-    if (!isExists) {
-      myConstraints.push_back(aPonCurveConstr);
-      aConstrList.push_back(aPonCurveConstr.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>(
-          aConstrData->attribute(aConstraintAttributes[indAttr]));
-      addTemporaryConstraintWhereDragged(aConstrAttr->attr());
-      continue;
-    }
-    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;
-}
-
-// ============================================================================
-//  Function: changeEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the element affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
-    std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
-  // If the entity is already in the group, try to find it
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
-      myEntityAttrMap.find(theEntity);
-  int aEntPos;
-  std::vector<Slvs_Param>::iterator aParamIter;  // looks at first parameter of already existent entity or at the end of vector otherwise
-  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
-    aParamIter = myParams.end();
-  else {  // the entity already exists
-    aEntPos = Search(aEntIter->second, myEntities);
-    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
-    aParamIter = myParams.begin() + aParamPos;
-  }
-  const bool isEntExists = (aEntIter != myEntityAttrMap.end());  // defines that the entity already exists
-  const bool isNeedToSolve = myNeedToSolve;
-  myNeedToSolve = false;
-
-  if (isEntExists) {
-    // Verify that the entity is not used by "Rigid" constraint.
-    // If it is used, the object should not move.
-    std::vector<std::set<Slvs_hEntity> >::iterator aCoincIter = myCoincidentPoints.begin();
-    for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++)
-      if (aCoincIter->find(aEntIter->second) != aCoincIter->end())
-        break;
-    std::set<Slvs_hEntity> aCoincident;
-    if (aCoincIter != myCoincidentPoints.end()) {
-      aCoincident = *aCoincIter;
-      aCoincident.erase(aEntIter->second);
-
-      std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-      for (; aConstrIter != myConstraints.end(); aConstrIter++)
-        if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
-            aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
-          myNeedToSolve = true;
-          return aEntIter->second;
-        }
-    }
-  }
-
-  // Look over supported types of entities
-  Slvs_Entity aNewEntity;
-  aNewEntity.h = SLVS_E_UNKNOWN;
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-      theEntity);
-  if (aPoint) {
-    Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
-    Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
-    Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
-    if (!isEntExists) // New entity
-      aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
-  } else {
-    // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
-    if (myWorkplane.h == SLVS_E_UNKNOWN)
-      return SLVS_E_UNKNOWN;
-
-    // Point in 2D
-    std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
-    if (aPoint2D) {
-      Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
-      Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
-    } else {
-      // Scalar value (used for the distance entities)
-      AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
-      if (aScalar) {
-        Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
-        if (!isEntExists) // New entity
-          aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
-      }
-    }
-  }
-  /// \todo Other types of entities
-
-  Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type
-
-  if (isEntExists) {
-    myNeedToSolve = myNeedToSolve || isNeedToSolve;
-    aResult = aEntIter->second;
-  } else if (aNewEntity.h != SLVS_E_UNKNOWN) {
-    myEntities.push_back(aNewEntity);
-    myEntOfConstr.push_back(false);
-    myEntityAttrMap[theEntity] = aNewEntity.h;
-    aResult = aNewEntity.h;
-  }
-
-  // If the attribute was changed by the user, we need to fix it before solving
-  if (myNeedToSolve && theEntity->isImmutable())
-    addTemporaryConstraintWhereDragged(theEntity, false);
-
-  return aResult;
-}
-
-// ============================================================================
-//  Function: changeEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the element defined by the feature affected by any constraint
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity)
-{
-  if (!theEntity->data()->isValid())
-    return SLVS_E_UNKNOWN;
-  // If the entity is already in the group, try to find it
-  std::map<FeaturePtr, Slvs_hEntity>::const_iterator aEntIter = myEntityFeatMap.find(theEntity);
-  // defines that the entity already exists
-  const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
-  
-  Slvs_Entity aNewEntity;
-  aNewEntity.h = SLVS_E_UNKNOWN;
-
-  // SketchPlugin features
-  std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
-      SketchPlugin_Feature>(theEntity);
-  if (aFeature) {  // Verify the feature by its kind
-    const std::string& aFeatureKind = aFeature->getKind();
-    AttributePtr anAttribute;
-
-    // Line
-    if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute);
-
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
-    }
-    // Circle
-    else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aRadius = changeEntity(anAttribute);
-
-      if (!isEntExists) // New entity
-        aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter,
-                                     myWorkplane.normal, aRadius);
-    }
-    // Arc
-    else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aCenter = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aStart = changeEntity(anAttribute);
-
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aEnd = changeEntity(anAttribute);
-
-      if (!isEntExists)
-        aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h,
-                                          myWorkplane.normal, aCenter, aStart, aEnd);
-    }
-    // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
-    else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) {
-      anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID());
-      if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN;
-      Slvs_hEntity aPoint = changeEntity(anAttribute);
-
-      if (isEntExists)
-        return aEntIter->second;
-
-      // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
-      myEntityFeatMap[theEntity] = aPoint;
-      myNeedToSolve = true;
-      return aPoint;
-    }
-  }
-  /// \todo Other types of features
-
-  if (isEntExists)
-    return aEntIter->second;
-
-  if (aNewEntity.h != SLVS_E_UNKNOWN) {
-    myEntities.push_back(aNewEntity);
-    myEntOfConstr.push_back(false);
-    myEntityFeatMap[theEntity] = aNewEntity.h;
-    myNeedToSolve = true;
-    return aNewEntity.h;
-  }
-
-  // Unsupported or wrong entity type
-  return SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-//  Function: changeNormal
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update the normal of workplane
-// ============================================================================
-Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal(
-    std::shared_ptr<ModelAPI_Attribute> theDirX,
-    std::shared_ptr<ModelAPI_Attribute> theNorm)
-{
-  std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNorm);
-  std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
-  if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance))
-    return SLVS_E_UNKNOWN;
-  // calculate Y direction
-  std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir())));
-
-  // quaternion parameters of normal vector
-  double qw, qx, qy, qz;
-  Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw,
-                      &qx, &qy, &qz);
-  double aNormCoord[4] = { qw, qx, qy, qz };
-
-  // Try to find existent normal
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aEntIter =
-      myEntityAttrMap.find(theNorm);
-  std::vector<Slvs_Param>::iterator aParamIter;  // looks to the first parameter of already existent entity or to the end of vector otherwise
-  if (aEntIter == myEntityAttrMap.end())  // no such entity => should be created
-    aParamIter = myParams.end();
-  else {  // the entity already exists, update it
-    int aEntPos = Search(aEntIter->second, myEntities);
-    int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
-    aParamIter = myParams.begin() + aParamPos;
-  }
-
-  // Change parameters of the normal
-  Slvs_hParam aNormParams[4];
-  for (int i = 0; i < 4; i++)
-    aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
-
-  if (aEntIter != myEntityAttrMap.end())  // the entity already exists
-    return aEntIter->second;
-
-  // Create a normal
-  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1],
-                                          aNormParams[2], aNormParams[3]);
-  myEntities.push_back(aNormal);
-  myEntOfConstr.push_back(false);
-  myEntityAttrMap[theNorm] = aNormal.h;
-  return aNormal.h;
-}
-
-// ============================================================================
-//  Function: addWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create workplane for the group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
-{
-  if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0)
-    return false;  // the workplane already exists or the function parameter is not Sketch
-
-  mySketch = theSketch;
-  updateWorkplane();
-  return true;
-}
-
-// ============================================================================
-//  Function: updateWorkplane
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  update parameters of workplane
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateWorkplane()
-{
-  if (!mySketch->data())
-    return false; // case sketch is deleted
-  // Get parameters of workplane
-  std::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(
-      SketchPlugin_Sketch::DIRX_ID());
-  std::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(
-      SketchPlugin_Sketch::NORM_ID());
-  std::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(
-      SketchPlugin_Sketch::ORIGIN_ID());
-  // Transform them into SolveSpace format
-  Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm);
-  if (!aNormalWP)
-    return false;
-  Slvs_hEntity anOriginWP = changeEntity(anOrigin);
-  if (!anOriginWP)
-    return false;
-
-  if (!myWorkplane.h) {
-    // Create workplane
-    myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
-    // Workplane should be added to the list of entities
-    myEntities.push_back(myWorkplane);
-    myEntOfConstr.push_back(false);
-  }
-  return true;
-}
-
-// ============================================================================
-//  Function: changeParameter
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  create/update value of parameter
-// ============================================================================
-Slvs_hParam SketchSolver_ConstraintGroup::changeParameter(
-    double theParam, std::vector<Slvs_Param>::iterator& thePrmIter)
-{
-  if (thePrmIter != myParams.end()) {  // Parameter should be updated
-    int aParamPos = thePrmIter - myParams.begin();
-    if (fabs(thePrmIter->val - theParam) > tolerance) {
-      myNeedToSolve = true;  // parameter is changed, need to resolve constraints
-      myParams[aParamPos].val = theParam;
-    }
-    thePrmIter++;
-    return myParams[aParamPos].h;
-  }
-
-  // Newly created parameter
-  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
-  myParams.push_back(aParam);
-  myNeedToSolve = true;
-  // The list of parameters is changed, move iterator to the end of the list to avoid problems
-  thePrmIter = myParams.end();
-  return aParam.h;
-}
-
-// ============================================================================
-//  Function: resolveConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  solve the set of constraints for the current group
-// ============================================================================
-bool SketchSolver_ConstraintGroup::resolveConstraints()
-{
-  if (!myNeedToSolve)
-    return false;
-
-  myConstrSolver.setGroupID(myID);
-  myConstrSolver.setParameters(myParams);
-  myConstrSolver.setEntities(myEntities);
-  myConstrSolver.setConstraints(myConstraints);
-  myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
-
-  int aResult = myConstrSolver.solve();
-  if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
-                                      // Obtain result into the same list of parameters
-    if (!myConstrSolver.getResult(myParams))
-      return true;
-
-    // We should go through the attributes map, because only attributes have valued parameters
-    std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntIter =
-        myEntityAttrMap.begin();
-    for (; anEntIter != myEntityAttrMap.end(); anEntIter++) {
-      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
-        anEntIter->first->owner()->data()->blockSendAttributeUpdated(true);
-      if (updateAttribute(anEntIter->first, anEntIter->second))
-        updateRelatedConstraints(anEntIter->first);
-    }
-    updateFilletConstraints();
-    // unblock all features then
-    for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) {
-      if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get())
-        anEntIter->first->owner()->data()->blockSendAttributeUpdated(false);
-    }
-  } else if (!myConstraints.empty())
-    Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
-
-  removeTemporaryConstraints();
-  myNeedToSolve = false;
-  return true;
-}
-
-// ============================================================================
-//  Function: mergeGroups
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  append specified group to the current group
-// ============================================================================
-void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup)
-{
-  // If specified group is empty, no need to merge
-  if (theGroup.myConstraintMap.empty())
-    return;
-
-  // Map between old and new indexes of SolveSpace constraints
-  std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
-
-  // Add all constraints from theGroup to the current group
-  ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin();
-  for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
-    if (changeConstraint(aConstrIter->first))
-      aConstrMap[aConstrIter->second.back()] = myConstrMaxID;  // the constraint was added => store its ID
-
-  // Add temporary constraints from theGroup
-  std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
-  for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) {
-    std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(
-        *aTempConstrIter);
-    if (aFind != aConstrMap.end())
-      myTempConstraints.push_back(aFind->second);
-  }
-
-  if (myTempPointWhereDragged.empty())
-    myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
-  else if (!theGroup.myTempPointWhereDragged.empty()) {  // Need to create additional transient constraint
-    std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator aFeatureIter =
-        theGroup.myEntityAttrMap.begin();
-    for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
-      if (aFeatureIter->second == myTempPointWDrgdID) {
-        addTemporaryConstraintWhereDragged(aFeatureIter->first);
-        break;
-      }
-  }
-
-  myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
-}
-
-// ============================================================================
-//  Function: splitGroup
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  divide the group into several subgroups
-// ============================================================================
-void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
-{
-  // Divide constraints and entities into several groups
-  std::vector<std::set<Slvs_hEntity> > aGroupsEntities;
-  std::vector<std::set<Slvs_hConstraint> > aGroupsConstr;
-  int aMaxNbEntities = 0;  // index of the group with maximal nuber of elements (this group will be left in the current)
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++) {
-    Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA,
-        aConstrIter->entityB };
-    std::vector<int> anIndexes;
-    // Go through the groupped entities and find even one of entities of current constraint
-    std::vector<std::set<Slvs_hEntity> >::iterator aGrEntIter;
-    for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) {
-      bool isFound = false;
-      for (int i = 0; i < 4 && !isFound; i++)
-        if (aConstrEnt[i] != 0) {
-          isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
-          // Also we need to check sub-entities
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++)
-              isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end());
-          }
-        }
-      if (isFound)
-        anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
-    }
-    // Add new group if no one is found
-    if (anIndexes.empty()) {
-      std::set<Slvs_hEntity> aNewGrEnt;
-      for (int i = 0; i < 4; i++)
-        if (aConstrEnt[i] != 0) {
-          aNewGrEnt.insert(aConstrEnt[i]);
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
-              aNewGrEnt.insert(*aSub);
-          }
-        }
-      std::set<Slvs_hConstraint> aNewGrConstr;
-      aNewGrConstr.insert(aConstrIter->h);
-
-      aGroupsEntities.push_back(aNewGrEnt);
-      aGroupsConstr.push_back(aNewGrConstr);
-      if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
-        aMaxNbEntities = aGroupsEntities.size() - 1;
-    } else {  // Add entities indexes into the found group
-      aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
-      for (int i = 0; i < 4; i++)
-        if (aConstrEnt[i] != 0) {
-          aGrEntIter->insert(aConstrEnt[i]);
-          int aEntPos = Search(aConstrEnt[i], myEntities);
-          if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close
-            Slvs_hEntity* aSub = myEntities[aEntPos].point;
-            for (int j = 0; *aSub != 0 && j < 4; aSub++, j++)
-              aGrEntIter->insert(*aSub);
-          }
-        }
-      aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
-      if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
-        aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
-      if (anIndexes.size() > 1) {  // There are found several connected groups, merge them
-        std::vector<std::set<Slvs_hEntity> >::iterator aFirstGroup = aGroupsEntities.begin()
-            + anIndexes.front();
-        std::vector<std::set<Slvs_hConstraint> >::iterator aFirstConstr = aGroupsConstr.begin()
-            + anIndexes.front();
-        std::vector<int>::iterator anInd = anIndexes.begin();
-        for (++anInd; anInd != anIndexes.end(); anInd++) {
-          aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
-          aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
-        }
-        if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
-          aMaxNbEntities = anIndexes.front();
-        // Remove merged groups
-        for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) {
-          aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
-          aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
-        }
-      }
-    }
-  }
-
-  if (aGroupsEntities.size() <= 1)
-    return;
-
-  // Remove the group with maximum elements as it will be left in the current group
-  aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
-  aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
-
-  // Add new groups of constraints and divide current group
-  std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
-  for (int i = aGroupsEntities.size(); i > 0; i--) {
-    SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
-    aNewGroups.push_back(aG);
-  }
-  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin();
-  int aConstrMapPos = 0;  // position of iterator in the map (used to restore iterator after removing constraint)
-  while (aConstrMapIter != myConstraintMap.end()) {
-    std::vector<std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
-    for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
-      if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) {
-        (*aGroup)->changeConstraint(aConstrMapIter->first);
-        removeConstraint(aConstrMapIter->first);
-        // restore iterator
-        aConstrMapIter = myConstraintMap.begin();
-        for (int i = 0; i < aConstrMapPos; i++)
-          aConstrMapIter++;
-        break;
-      }
-    if (aGIter == aGroupsConstr.end()) {
-      aConstrMapIter++;
-      aConstrMapPos++;
-    }
-  }
-
-  theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
-}
-
-// ============================================================================
-//  Function: updateGroup
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  search removed entities and constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateGroup()
-{
-  ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin();
-  bool isAllValid = true;
-  bool isCCRemoved = false;  // indicates that at least one of coincidence constraints was removed
-  int aConstrIndex = 0;
-  while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) {
-    if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) {
-      if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0)
-        isCCRemoved = true;
-      removeConstraint(aConstrIter->first);
-      isAllValid = false;
-      // Get back the correct position of iterator after the "remove" operation
-      aConstrIter = myConstraintMap.rbegin();
-      for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++)
-        aConstrIter++;
-    } else {
-      aConstrIter++;
-      aConstrIndex++;
-    }
-  }
-
-  // Check if some entities are invalid too
-  std::set<Slvs_hEntity> anEntToRemove;
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
-      anAttrIter = myEntityAttrMap.begin();
-  while (anAttrIter != myEntityAttrMap.end()) {
-    if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() ||
-        !anAttrIter->first->owner()->data()->isValid()) {
-      anEntToRemove.insert(anAttrIter->second);
-      std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
-          aRemovedIter = anAttrIter;
-      anAttrIter++;
-      myEntityAttrMap.erase(aRemovedIter);
-    } else
-      anAttrIter++;
-  }
-  std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myEntityFeatMap.begin();
-  while (aFeatIter != myEntityFeatMap.end()) {
-    if (!aFeatIter->first || !aFeatIter->first->data() ||
-        !aFeatIter->first->data()->isValid()) {
-      anEntToRemove.insert(aFeatIter->second);
-      std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = aFeatIter;
-      aFeatIter++;
-      myEntityFeatMap.erase(aRemovedIter);
-    } else
-      aFeatIter++;
-  }
-  removeEntitiesById(anEntToRemove);
-
-  // Probably, need to update coincidence constraints
-  if (isCCRemoved && !myExtraCoincidence.empty()) {
-    // Make a copy, because the new list of unused constrtaints will be generated
-    std::set<std::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
-    myExtraCoincidence.clear();
-
-    std::set<std::shared_ptr<SketchPlugin_Constraint> >::iterator aCIter = anExtraCopy.begin();
-    for (; aCIter != anExtraCopy.end(); aCIter++)
-      if ((*aCIter)->data() && (*aCIter)->data()->isValid())
-        changeConstraint(*aCIter);
-  }
-
-  return !isAllValid;
-}
-
-// ============================================================================
-//  Function: updateAttribute
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  update features of sketch after resolving constraints
-// ============================================================================
-bool SketchSolver_ConstraintGroup::updateAttribute(
-    std::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID)
-{
-  // Search the position of the first parameter of the entity
-  int anEntPos = Search(theEntityID, myEntities);
-  int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
-
-  // Look over supported types of entities
-
-  // Point in 3D
-  std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-      theAttribute);
-  if (aPoint) {
-    if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance
-        || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance
-        || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) {
-      aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val,
-                       myParams[aFirstParamPos + 2].val);
-      return true;
-    }
-    return false;
-  }
-
-  // Point in 2D
-  std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
-      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
-  if (aPoint2D) {
-    if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance
-        || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) {
-      aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val);
-      return true;
-    }
-    return false;
-  }
-
-  // Scalar value
-  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
-  if (aScalar) {
-    if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) {
-      aScalar->setValue(myParams[aFirstParamPos].val);
-      return true;
-    }
-    return false;
-  }
-
-  /// \todo Support other types of entities
-  return false;
-}
-
-// ============================================================================
-//  Function: updateEntityIfPossible
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  search the entity in this group and update it
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateEntityIfPossible(
-    std::shared_ptr<ModelAPI_Attribute> theEntity)
-{
-  if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) {
-    // If the attribute is a point and it is changed (the group needs to rebuild),
-    // probably user has dragged this point into this position,
-    // so it is necessary to add constraint which will guarantee the point will not change
-
-    // Store myNeedToSolve flag to verify the entity is really changed
-    bool aNeedToSolveCopy = myNeedToSolve;
-    myNeedToSolve = false;
-
-    changeEntity(theEntity);
-
-    if (myNeedToSolve)  // the entity is changed
-    {
-      // Verify the entity is a point and add temporary constraint of permanency
-      std::shared_ptr<GeomDataAPI_Point> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point>(
-          theEntity);
-      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = std::dynamic_pointer_cast<
-          GeomDataAPI_Point2D>(theEntity);
-      if (aPoint || aPoint2D)
-        addTemporaryConstraintWhereDragged(theEntity);
-    }
-
-    // Restore flag of changes
-    myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
-
-    if (myNeedToSolve)
-      updateRelatedConstraints(theEntity);
-  }
-}
-
-// ============================================================================
-//  Function: addTemporaryConstraintWhereDragged
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  add transient constraint SLVS_C_WHERE_DRAGGED for the entity, 
-//            which was moved by user
-// ============================================================================
-void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
-    std::shared_ptr<ModelAPI_Attribute> theEntity,
-    bool theAllowToFit)
-{
-  // Find identifier of the entity
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
-      myEntityAttrMap.find(theEntity);
-  if (anEntIter == myEntityAttrMap.end())
-    return;
-
-  // Get identifiers of all dragged points
-  std::set<Slvs_hEntity> aDraggedPntID;
-  aDraggedPntID.insert(myTempPointWDrgdID);
-  std::list<Slvs_hConstraint>::const_iterator aTmpCoIter = myTempConstraints.begin();
-  for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) {
-    unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
-    if (aConstrPos < myConstraints.size())
-      aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
-  }
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++)
-    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED)
-      aDraggedPntID.insert(aConstrIter->ptA);
-  // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
-  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-  for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) {
-    if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
-      continue;  // the entity was not found in current set
-
-    // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
-    std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
-    for (; aDrgIter != aDraggedPntID.end(); aDrgIter++)
-      if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
-        return;  // the SLVS_C_WHERE_DRAGGED constraint already exists
-  }
-  if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end())
-    return;
-
-  // If this is a first dragged point, its parameters should be placed 
-  // into Slvs_System::dragged field to avoid system inconsistense
-  if (myTempPointWhereDragged.empty() && theAllowToFit) {
-    int anEntPos = Search(anEntIter->second, myEntities);
-    Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
-    for (int i = 0; i < 4; i++, aDraggedParam++)
-      if (*aDraggedParam != 0)
-        myTempPointWhereDragged.push_back(*aDraggedParam);
-    myTempPointWDrgdID = myEntities[anEntPos].h;
-    return;
-  }
-
-  // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
-  Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
-                                                  myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
-  myConstraints.push_back(aWDConstr);
-  myTempConstraints.push_back(aWDConstr.h);
-}
-
-// ============================================================================
-//  Function: removeTemporaryConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
-//            resolving the set of constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeTemporaryConstraints(
-    const std::set<Slvs_hConstraint>& theRemoved)
-{
-  std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
-  for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend();
-      aTmpConstrIter++) {
-    if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end())
-      continue;
-    unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
-    if (aConstrPos >= myConstraints.size())
-      continue;
-    myConstraints.erase(myConstraints.begin() + aConstrPos);
-
-    // If the removing constraint has higher index, decrease the indexer
-    if (*aTmpConstrIter == myConstrMaxID)
-      myConstrMaxID--;
-  }
-  myTempConstraints.clear();
-
-  // Clear basic dragged point
-  myTempPointWhereDragged.clear();
-  myTempPointWDrgdID = SLVS_E_UNKNOWN;
-}
-
-// ============================================================================
-//  Function: removeConstraint
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  remove constraint and all unused entities
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeConstraint(
-    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
-  ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint);
-  if (anIterToRemove == myConstraintMap.end())
-    return;
-
-  std::vector<Slvs_hConstraint> aCnstrToRemove = anIterToRemove->second;
-  // Remove constraint from the map
-  myConstraintMap.erase(anIterToRemove);
-
-  std::set<Slvs_hEntity> anEntToRemove;
-  
-  // Find unused entities
-  std::vector<Slvs_hConstraint>::iterator aCnstrToRemoveIter = aCnstrToRemove.begin();
-  for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) {
-    int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints);
-    Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
-        myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB };
-    for (int i = 0; i < 4; i++)
-      if (aCnstEnt[i] != 0)
-        anEntToRemove.insert(aCnstEnt[i]);
-    myConstraints.erase(myConstraints.begin() + aConstrPos);
-    if (*aCnstrToRemoveIter == myConstrMaxID)
-      myConstrMaxID--;
-  }
-
-  // Find all entities which are based on these unused
-  std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
-  for ( ; anEntIter != myEntities.end(); anEntIter++)
-    if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE ||
-        anEntIter->type == SLVS_E_ARC_OF_CIRCLE) {
-      for (int i = 0; i < 4; i++)
-        if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) {
-          anEntToRemove.insert(anEntIter->h);
-          for (int j = 0; j < 4; j++)
-            if (anEntIter->point[j] != 0)
-              anEntToRemove.insert(anEntIter->point[j]);
-          break;
-        }
-    }
-
-  // Find entities used by remaining constraints and remove them from the list to delete
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
-  for (; aConstrIter != myConstraints.end(); aConstrIter++) {
-    Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter
-        ->entityB };
-    for (int i = 0; i < 4; i++)
-      if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) {
-        anEntToRemove.erase(aEnts[i]);
-        // remove from the list all points of current entity
-        int aEntPos = Search(aEnts[i], myEntities);
-        for (int j = 0; j < 4; j++)
-          if (myEntities[aEntPos].point[j] != 0)
-            anEntToRemove.erase(myEntities[aEntPos].point[j]);
-      }
-  }
-
-  if (anEntToRemove.empty())
-    return;
-
-  // Remove unused entities
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator anEntAttrIter =
-      myEntityAttrMap.begin();
-  while (anEntAttrIter != myEntityAttrMap.end()) {
-    if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) {
-      std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator aRemovedIter =
-          anEntAttrIter;
-      anEntAttrIter++;
-      myEntityAttrMap.erase(aRemovedIter);
-    } else
-      anEntAttrIter++;
-  }
-  std::map<FeaturePtr, Slvs_hEntity>::iterator anEntFeatIter = myEntityFeatMap.begin();
-  while (anEntFeatIter != myEntityFeatMap.end()) {
-    if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) {
-      std::map<FeaturePtr, Slvs_hEntity>::iterator aRemovedIter = anEntFeatIter;
-      anEntFeatIter++;
-      myEntityFeatMap.erase(aRemovedIter);
-    } else
-      anEntFeatIter++;
-  }
-
-  removeEntitiesById(anEntToRemove);
-
-  if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
-    myCoincidentPoints.clear();
-}
-
-// ============================================================================
-//  Function: removeEntitiesById
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  Removes specified entities and their parameters
-// ============================================================================
-void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set<Slvs_hEntity>& theEntities)
-{
-  std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = theEntities.rbegin();
-  for (; aRemIter != theEntities.rend(); aRemIter++) {
-    unsigned int anEntPos = Search(*aRemIter, myEntities);
-    if (anEntPos >= myEntities.size())
-      continue;
-    if (myEntities[anEntPos].param[0] != 0) {
-      unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
-      if (aParamPos >= myParams.size())
-        continue;
-      int aNbParams = 0;
-      while (myEntities[anEntPos].param[aNbParams] != 0)
-        aNbParams++;
-      if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID)
-        myParamMaxID -= aNbParams;
-      myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
-      if (*aRemIter == myEntityMaxID)
-        myEntityMaxID--;
-    }
-    myEntities.erase(myEntities.begin() + anEntPos);
-    myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos);
-
-    // Remove entity's ID from the lists of conincident points
-    std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-    for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
-      aCoPtIter->erase(*aRemIter);
-  }
-}
-
-// ============================================================================
-//  Function: addCoincidentPoints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  add coincident point the appropriate list of such points
-// ============================================================================
-bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1,
-                                                       const Slvs_hEntity& thePoint2)
-{
-  std::vector<std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
-  std::vector<std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
-  while (aCoPtIter != myCoincidentPoints.end()) {
-    bool isFound[2] = {  // indicate which point ID was already in coincidence constraint
-        aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2)
-            != aCoPtIter->end(), };
-    if (isFound[0] && isFound[1])  // points are already connected by coincidence constraints => no need additional one
-      return false;
-    if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) {
-      if (aFirstFound != myCoincidentPoints.end()) {  // there are two groups of coincident points connected by created constraint => merge them
-        int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
-        int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
-        aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
-        myCoincidentPoints.erase(aCoPtIter);
-        aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
-        aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
-        continue;
-      } else {
-        aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
-        aFirstFound = aCoPtIter;
-      }
-    }
-    aCoPtIter++;
-  }
-  // No points were found, need to create new set
-  if (aFirstFound == myCoincidentPoints.end()) {
-    std::set<Slvs_hEntity> aNewSet;
-    aNewSet.insert(thePoint1);
-    aNewSet.insert(thePoint2);
-    myCoincidentPoints.push_back(aNewSet);
-  }
-
-  return true;
-}
-
-// ============================================================================
-//  Function: updateRelatedConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  emit the signal to update constraints
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateRelatedConstraints(
-    std::shared_ptr<ModelAPI_Attribute> theEntity) const
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-        ->attributes(std::string());
-
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-      bool isUpd = (*anAttrIter == theEntity);
-      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-          ModelAPI_AttributeRefAttr>(*anAttrIter);
-      if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity)
-        isUpd = true;
-
-      if (isUpd) {
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-        break;
-      }
-    }
-  }
-}
-
-void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature(
-    std::shared_ptr<ModelAPI_Feature> theFeature) const
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++) {
-    std::list<std::shared_ptr<ModelAPI_Attribute> > anAttributes = aConstrIter->first->data()
-        ->attributes(std::string());
-
-    std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttributes.begin();
-    for (; anAttrIter != anAttributes.end(); anAttrIter++) {
-      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr = std::dynamic_pointer_cast<
-          ModelAPI_AttributeRefAttr>(*anAttrIter);
-      if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) {
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
-        ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent);
-        break;
-      }
-    }
-  }
-}
-
-// ============================================================================
-//  Function: updateFilletConstraints
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  change fillet arc to be less than 180 degree
-// ============================================================================
-void SketchSolver_ConstraintGroup::updateFilletConstraints()
-{
-  ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin();
-  for (; aConstrIter != myConstraintMap.end(); aConstrIter++)
-    if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) {
-      AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
-          aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C()));
-      if (!aFilletRefList)
-        return;
-      ObjectPtr anArcObj = aFilletRefList->object(2);
-      std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID()));
-      std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::START_ID()));
-      std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-          anArcObj->data()->attribute(SketchPlugin_Arc::END_ID()));
-      double aCosA = aStart->x() - aCenter->x();
-      double aSinA = aStart->y() - aCenter->y();
-      double aCosB = aEnd->x() - aCenter->x();
-      double aSinB = aEnd->y() - aCenter->y();
-      if (aCosA * aSinB - aSinA * aCosB <= 0.0) {
-        anArcObj->data()->blockSendAttributeUpdated(true);
-        double x = aStart->x();
-        double y = aStart->y();
-        aStart->setValue(aEnd->x(), aEnd->y());
-        aEnd->setValue(x, y);
-        // Update constraint data
-        changeFilletConstraint(aConstrIter->first);
-        anArcObj->data()->blockSendAttributeUpdated(false);
-      }
-    }
-}
-
-// ============================================================================
-//  Function: makeMirrorEntity
-//  Class:    SketchSolver_ConstraintGroup
-//  Purpose:  change entities parameters to make them symmetric relating to the mirror line
-// ============================================================================
-void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase,
-                                                    const Slvs_hEntity& theMirror,
-                                                    const Slvs_hEntity& theMirrorLine)
-{
-  Slvs_Entity aBase = myEntities[Search(theBase, myEntities)];
-  Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)];
-  int i = 0;
-  if (aBase.type != SLVS_E_ARC_OF_CIRCLE) {
-    while (aBase.point[i] != 0 && aMirror.point[i] != 0) {
-      makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine);
-      i++;
-    }
-  } else {
-    // swap mirroring first and last points of an arc
-    makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine);
-    makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine);
-    makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine);
-  }
-  if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it
-    Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)];
-    std::shared_ptr<GeomAPI_XY> aLinePoints[2];
-    for (i = 0; i < 2; i++) {
-      Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)];
-      int aParamPos = Search(aPoint.param[0], myParams);
-      aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
-          new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val));
-    }
-    int aBaseParamPos = Search(aBase.param[0], myParams);
-    int aMirrorParamPos = Search(aMirror.param[0], myParams);
-    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val));
-
-    // direction of a mirror line
-    std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
-        new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
-    // orthogonal direction
-    aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
-    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
-        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
-    double aDist = aVec->dot(aDir->xy());
-    std::shared_ptr<GeomAPI_XY> aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
-    myParams[aMirrorParamPos].val = aMirrorPoint->x();
-    myParams[1+aMirrorParamPos].val = aMirrorPoint->y();
-  }
-}
-
-// ============================================================================
-//  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>::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
-//  Purpose:  calculates middle point on line or arc
-// ============================================================================
-void SketchSolver_ConstraintGroup::calculateMiddlePoint(
-    const Slvs_hEntity& theEntity,
-    double& theX,
-    double& theY) const
-{
-  int anInd = Search(theEntity, myEntities);
-  if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) {
-    int aLineParams[2];
-    for (int i = 0; i < 2; i++) {
-      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-      aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams);
-    }
-    theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val);
-    theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val);
-  } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) {
-    double anArcPoint[3][2];
-    for (int i = 0; i < 3; i++) {
-      int aPtPos = Search(myEntities[anInd].point[i], myEntities);
-      int anArcParam = Search(myEntities[aPtPos].param[0], myParams);
-      anArcPoint[i][0] = myParams[anArcParam].val;
-      anArcPoint[i][1] = myParams[1 + anArcParam].val;
-    }
-    // project last point of arc on the arc
-    double x = anArcPoint[1][0] - anArcPoint[0][0];
-    double y = anArcPoint[1][1] - anArcPoint[0][1];
-    double aRad = sqrt(x*x + y*y);
-    x = anArcPoint[2][0] - anArcPoint[0][0];
-    y = anArcPoint[2][1] - anArcPoint[0][1];
-    double aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      anArcPoint[2][0] = anArcPoint[0][0] + x * aRad / aNorm;
-      anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm;
-    }
-
-    x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0];
-    y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1];
-    aNorm = sqrt(x*x + y*y);
-    if (aNorm >= tolerance) {
-      x *= aRad / aNorm;
-      y *= aRad / aNorm;
-    } else { // obtain orthogonal direction
-      x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]);
-      y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]);
-    }
-    theX = anArcPoint[0][0] + x;
-    theY = anArcPoint[0][1] + y;
-  }
-}
-
-
-// ========================================================
-// =========      Auxiliary functions       ===============
-// ========================================================
-
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
-{
-  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
-  int aVecSize = theEntities.size();
-  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
-    aResIndex--;
-  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
-    aResIndex++;
-  if (aResIndex == -1)
-    aResIndex = aVecSize;
-  return aResIndex;
-}
diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.h b/src/SketchSolver/SketchSolver_ConstraintGroup.h
deleted file mode 100644 (file)
index 8ec2685..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:    SketchSolver_ConstraintGroup.h
-// Created: 27 May 2014
-// Author:  Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintGroup_H_
-#define SketchSolver_ConstraintGroup_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-
-#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Feature.h>
-
-
-#include <memory>
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-typedef std::map< std::shared_ptr<SketchPlugin_Constraint>, std::vector<Slvs_hConstraint> >
-  ConstraintMap;
-
-/** \class   SketchSolver_ConstraintGroup
- *  \ingroup Plugins
- *  \brief   Keeps the group of constraints which based on the same entities
- */
-class SketchSolver_ConstraintGroup
-{
- public:
-  /** \brief New group based on specified workplane.
-   *         Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
-   *  \remark Type of theSketch is not verified inside
-   */
-  SketchSolver_ConstraintGroup(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
-
-  ~SketchSolver_ConstraintGroup();
-
-  /// \brief Returns group's unique identifier
-  inline const Slvs_hGroup& getId() const
-  {
-    return myID;
-  }
-
-  /// \brief Returns true if the group has no constraints yet
-  inline bool isEmpty() const
-  {
-    return myConstraints.empty();
-  }
-
-  /// \brief Check for valid sketch data
-  inline bool isWorkplaneValid() const
-  {
-    return mySketch->data() && mySketch->data()->isValid();
-  }
-
-  /** \brief Adds or updates a constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a rigid constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a mirror constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-  /** \brief Adds or updates a fillet constraint in the group
-   *  \param[in] theConstraint constraint to be changed
-   *  \return \c true if the constraint added or updated successfully
-   */
-  bool changeFilletConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Verifies the feature attributes are used in this group
-   *  \param[in] theFeature constraint or any other object for verification of interaction
-   *  \return \c true if some of attributes are used in current group
-   */
-  bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
-  /** \brief Verifies the specified feature is equal to the base workplane for this group
-   *  \param[in] theWorkplane the feature to be compared with base workplane
-   *  \return \c true if workplanes are the same
-   */
-  bool isBaseWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane) const;
-
-  /// Returns the current workplane
-  std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
-  {
-    return mySketch;
-  }
-
-  /** \brief Update parameters of workplane. Should be called when Update event is coming.
-   *  \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
-   */
-  bool updateWorkplane();
-
-  /** \brief If the entity is in this group it will updated
-   *  \param[in] theEntity attribute, which values should update SolveSpace entity
-   */
-  void updateEntityIfPossible(std::shared_ptr<ModelAPI_Attribute> theEntity);
-
-  /** \brief Searches invalid features and constraints in the group and avoids them
-   *  \return \c true if the group several constraints were removed
-   */
-  bool updateGroup();
-
-  /** \brief Add specified group to this one
-   *  \param[in] theGroup group of constraint to be added
-   */
-  void mergeGroups(const SketchSolver_ConstraintGroup& theGroup);
-
-  /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
-   *  \param[out] theCuts enlarge this list by newly created groups
-   */
-  void splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts);
-
-  /** \brief Start solution procedure if necessary and update attributes of features
-   *  \return \c false when no need to solve constraints
-   */
-  bool resolveConstraints();
-
-  /** \brief Searches the constraints built on the entity and emit the signal to update them
-   *  \param[in] theEntity attribute of the constraint
-   */
-  void updateRelatedConstraints(std::shared_ptr<ModelAPI_Attribute> theEntity) const;
-  /** \brief Searches the constraints built on the entity and emit the signal to update them
-   *  \param[in] theFeature feature of the constraint
-   */
-  void updateRelatedConstraintsFeature(std::shared_ptr<ModelAPI_Feature> theFeature) const;
-
-  /** \brief Adds or updates an entity in the group
-   *
-   *  The parameters of entity will be parsed and added to the list of SolveSpace parameters.
-   *  Parameters of certain entity will be placed sequentially in the list.
-   *
-   *  \param[in] theEntity the object of constraint
-   *  \return identifier of changed entity or 0 if entity could not be changed
-   */
-  Slvs_hEntity changeEntity(std::shared_ptr<ModelAPI_Attribute> theEntity);
-  Slvs_hEntity changeEntityFeature(std::shared_ptr<ModelAPI_Feature> theEntity);
-
-protected:
-  /** \brief Adds or updates a normal in the group
-   *
-   *  Normal is a special entity in SolveSpace, which defines a direction in 3D and
-   *  a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
-   *
-   *  To define a normal there should be specified two coordinate axis
-   *  on the plane transversed to created normal.
-   *
-   *  \param[in] theDirX first coordinate axis of the plane
-   *  \param[in] theNorm attribute for the normal (used to identify newly created entity)
-   *  \return identifier of created or updated normal
-   */
-  Slvs_hEntity changeNormal(std::shared_ptr<ModelAPI_Attribute> theDirX,
-                            std::shared_ptr<ModelAPI_Attribute> theNorm);
-
-  /** \brief Adds or updates a parameter in the group
-   *  \param[in] theParam   the value of parameter
-   *  \param[in] thePrmIter the cell in the list of parameters which should be changed
-   *                        (the iterator will be increased if it does not reach the end of the list)
-   *  \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
-   */
-  Slvs_hParam changeParameter(double theParam,
-                              std::vector<Slvs_Param>::iterator& thePrmIter);
-
-  /** \brief Removes specified entities and their parameters
-   *  \param[in] theEntities  list of IDs of the entities to be removed
-   */
-  void removeEntitiesById(const std::set<Slvs_hEntity>& theEntities);
-
-  /** \brief Removes constraints from the group
-   *  \param[in] theConstraint constraint to be removed
-   */
-  void removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
-  /** \brief Change values of attribute by parameters received from SolveSpace solver
-   *  \param[in,out] theAttribute pointer to the attribute to be changed
-   *  \param[in]     theEntityID  identifier of SolveSpace entity, which contains updated data
-   *  \return \c true if the attribute's value has changed
-   */
-  bool updateAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
-                       const Slvs_hEntity& theEntityID);
-
-  /// \brief Update arc of fillet to be less than 180 degree
-  void updateFilletConstraints();
-
-  /** \brief Adds a constraint for a point which should not be changed during computations
-   *  \param[in] theEntity     the base for the constraint
-   *  \param[in] theAllowToFit this flag shows that the entity may be placed into 
-   *                           the 'dragged' field of SolveSpace solver, so this entity 
-   *                           may be changed a little during solution
-   */
-  void addTemporaryConstraintWhereDragged(std::shared_ptr<ModelAPI_Attribute> theEntity,
-                                          bool theAllowToFit = true);
-
-  /** \brief Remove all temporary constraint after computation finished
-   *  \param[in] theRemoved  indexes of constraints to be removed. If empty, all temporary constraints should be deleted
-   */
-  void removeTemporaryConstraints(const std::set<Slvs_hConstraint>& theRemoved =
-                                                                 std::set<Slvs_hConstraint>());
-
- private:
-  /** \brief Creates a workplane from the sketch parameters
-   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
-   *  \return \c true if success, \c false if workplane parameters are not consistent
-   */
-  bool addWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
-
-  /** \brief Add the entities of constraint for points coincidence into the appropriate list
-   *  \param[in] thePoint1 identifier of the first point
-   *  \param[in] thePoint2 identifier of the second point
-   *  \return \c true if the points are added successfully, and 
-   *          \c false if the constraint is the extra one (should not be created in SolveSpace)
-   */
-  bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
-
-  /** \brief Verifies and changes parameters of constriant, 
-   *         e.g. sign of the distance between line and point
-   *  \param[in,out] theConstraint SolveSpace constraint to be verified
-   */
-  void checkConstraintConsistence(Slvs_Constraint& theConstraint);
-
-  /** \brief Change entities parameters to make them symmetric relating to the mirror line
-   *  \param[in] theBase        entity to be mirrored
-   *  \param[in] theMirror      a mirrored object
-   *  \param[in] theMirrorLine  a mirror line
-   */
-  void makeMirrorEntity(const Slvs_hEntity& theBase,
-                        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
-   *  \param[out] theY       Y value of middle point
-   */
-  void calculateMiddlePoint(const Slvs_hEntity& theEntity,
-                            double& theX, double& theY) const;
-
- private:
-  // SolveSpace entities
-  Slvs_hGroup myID;            ///< the index of the group
-  Slvs_Entity myWorkplane;     ///< Workplane for the current group
-  std::vector<Slvs_Param> myParams;        ///< List of parameters of the constraints
-  Slvs_hParam myParamMaxID;    ///< Actual maximal ID of parameters (not equal to myParams size)
-  std::vector<Slvs_Entity> myEntities;      ///< List of entities of the constaints
-  std::vector<bool> myEntOfConstr; ///< Flags show that certain entity used in constraints
-  Slvs_hEntity myEntityMaxID;   ///< Actual maximal ID of entities (not equal to myEntities size)
-  std::vector<Slvs_Constraint> myConstraints;   ///< List of constraints in SolveSpace format
-  Slvs_hConstraint myConstrMaxID;  ///< Actual maximal ID of constraints (not equal to myConstraints size)
-  bool myNeedToSolve;  ///< Indicator that something changed in the group and constraint system need to be rebuilt
-
-  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
-
-  std::vector<Slvs_hParam> myTempPointWhereDragged;  ///< Parameters of one of the points which is moved by user
-  Slvs_hEntity myTempPointWDrgdID;      ///< Identifier of such point
-  std::list<Slvs_hConstraint> myTempConstraints;  ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user
-
-  // SketchPlugin entities
-  std::shared_ptr<ModelAPI_CompositeFeature> mySketch;        ///< Equivalent to workplane
-  ConstraintMap myConstraintMap;  ///< The map between SketchPlugin and SolveSpace constraints
-  std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity> myEntityAttrMap;  ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities
-  std::map<FeaturePtr, Slvs_hEntity> myEntityFeatMap;  ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities
-
-  // Conincident items
-  std::vector<std::set<Slvs_hEntity> > myCoincidentPoints;  ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints)
-  std::set<std::shared_ptr<SketchPlugin_Constraint> > myExtraCoincidence;  ///< Additional coincidence constraints which are not necessary (coincidence between points already done
-                                                                             ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed
-};
-
-#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.cpp b/src/SketchSolver/SketchSolver_ConstraintLength.cpp
new file mode 100644 (file)
index 0000000..3d1d1bf
--- /dev/null
@@ -0,0 +1,36 @@
+#include <SketchSolver_ConstraintLength.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintLength::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntities;
+  getAttributes(aValue, anEntities);
+  if (!myErrorMsg.empty())
+    return;
+
+  // Check the entity is a line
+  Slvs_Entity aLine = myStorage->getEntity(anEntities[2]);
+  if (aLine.type != SLVS_E_LINE_SEGMENT){
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  }
+
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+      getType(), myGroup->getWorkplaneId(), aValue,
+      aLine.point[0], aLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+  aConstraint.h = myStorage->addConstraint(aConstraint);
+  mySlvsConstraints.push_back(aConstraint.h);
+  adjustConstraint();
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.h b/src/SketchSolver/SketchSolver_ConstraintLength.h
new file mode 100644 (file)
index 0000000..5d05837
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintLength.h
+// Created: 31 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintLength_H_
+#define SketchSolver_ConstraintLength_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintLength
+ *  \ingroup Plugins
+ *  \brief   Convert length constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintLength : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintLength(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_PT_PT_DISTANCE; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+};
+
+#endif
index bd346fb35fe35fac2343b7ff27b2600dae9c9544..d6094199f576d0f12f44be87a050c514606b2051 100644 (file)
@@ -5,7 +5,6 @@
 // Author:  Artem ZHIDKOV
 
 #include "SketchSolver_ConstraintManager.h"
-#include <SketchSolver_ConstraintGroup.h>
 
 #include <Events_Loop.h>
 #include <ModelAPI_AttributeDouble.h>
@@ -18,6 +17,9 @@
 
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintTangent.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Circle.h>
@@ -88,7 +90,7 @@ void SketchSolver_ConstraintManager::processEvent(
         std::shared_ptr<SketchPlugin_Feature> aSFeature = 
             std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
         if (aSFeature)
-          updateEntity(aSFeature);
+          moveEntity(aSFeature);
       }
     } else {
       std::set<ObjectPtr>::iterator aFeatIter;
@@ -105,19 +107,27 @@ void SketchSolver_ConstraintManager::processEvent(
         }
       }
       // then get anything but not the sketch
-      // at first, add coincidence constraints, because they may be used by other constraints
+      std::set<ObjectPtr> aComplexConstraints;
+      // fillet and mirror an tangency constraints will be processed later
       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())
+        if (!aFeature)
+          continue;
+        if (aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() ||
+            aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() ||
+            aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+          aComplexConstraints.insert(aFeature);
           continue;
+        }
         changeConstraintOrEntity(aFeature);
       }
-      // after that, add all features except coincidence
-      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+      // processing remain constraints
+      aFeatIter = aComplexConstraints.begin();
+      for (; aFeatIter != aComplexConstraints.end(); aFeatIter++) {
         std::shared_ptr<SketchPlugin_Feature> aFeature = 
           std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
-        if (!aFeature /*|| aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()*/)
+        if (!aFeature)
           continue;
         changeConstraintOrEntity(aFeature);
       }
@@ -138,8 +148,8 @@ void SketchSolver_ConstraintManager::processEvent(
         break;
 
     if (aFGrIter != aFeatureGroups.end()) {
-      std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
-      std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
+      std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+      std::vector<SketchSolver_Group*> aSeparatedGroups;
       while (aGroupIter != myGroups.end()) {
         if (!(*aGroupIter)->isWorkplaneValid()) {  // the group should be removed
           delete *aGroupIter;
@@ -148,7 +158,7 @@ void SketchSolver_ConstraintManager::processEvent(
           aGroupIter = myGroups.begin() + aShift;
           continue;
         }
-        if ((*aGroupIter)->updateGroup()) {  // some constraints were removed, try to split the group
+        if (!(*aGroupIter)->isConsistent()) {  // some constraints were removed, try to split the group
           (*aGroupIter)->splitGroup(aSeparatedGroups);
         }
         aGroupIter++;
@@ -164,13 +174,12 @@ void SketchSolver_ConstraintManager::processEvent(
 //  Class:    SketchSolver_Session
 //  Purpose:  update workplane by given parameters of the sketch
 // ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(
-    std::shared_ptr<ModelAPI_CompositeFeature> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
 {
   bool aResult = true;  // changed when a workplane wrongly updated
   bool isUpdated = false;
   // Try to update specified workplane in all groups
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
       isUpdated = true;
@@ -179,7 +188,7 @@ bool SketchSolver_ConstraintManager::changeWorkplane(
     }
   // If the workplane is not updated, so this is a new workplane
   if (!isUpdated) {
-    SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
+    SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
     // Verify that the group is created successfully
     if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
       delete aNewGroup;
@@ -213,7 +222,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
     std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
     if (!aWP)
       return false;
-    SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
+    SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
     if (!aGroup->changeConstraint(aConstraint)) {
       delete aGroup;
       return false;
@@ -222,19 +231,19 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
     return true;
   } else if (aGroups.size() == 1) {  // Only one group => add feature into it
     Slvs_hGroup aGroupId = *(aGroups.begin());
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+    std::vector<SketchSolver_Group*>::iterator aGroupIter;
     for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
       if ((*aGroupIter)->getId() == aGroupId) {
         // If the group is empty, the feature is not added (the constraint only)
         if (!aConstraint && !(*aGroupIter)->isEmpty())
-          return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+          return (*aGroupIter)->updateFeature(theFeature);
         return (*aGroupIter)->changeConstraint(aConstraint);
       }
   } else if (aGroups.size() > 1) {  // Several groups applicable for this feature => need to merge them
     std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
 
     // Search first group
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
+    std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
     for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
       if ((*aFirstGroupIter)->getId() == *aGroupsIter)
         break;
@@ -242,7 +251,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
       return false;
 
     // Append other groups to the first one
-    std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+    std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
     for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
       for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
         if ((*anOtherGroupIter)->getId() == *aGroupsIter)
@@ -263,7 +272,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
 
     if (aConstraint)
       return (*aFirstGroupIter)->changeConstraint(aConstraint);
-    return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN;
+    return (*aFirstGroupIter)->updateFeature(theFeature);
   }
 
   // Something goes wrong
@@ -271,54 +280,17 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
 }
 
 // ============================================================================
-//  Function: updateEntity
+//  Function: moveEntity
 //  Class:    SketchSolver_Session
-//  Purpose:  update any element on the sketch, which is used by constraints
+//  Purpose:  update element moved on the sketch, which is used by constraints
 // ============================================================================
-void SketchSolver_ConstraintManager::updateEntity(
+void SketchSolver_ConstraintManager::moveEntity(
     std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  // Create list of attributes depending on type of the feature
-  std::vector<std::string> anAttrList;
-  const std::string& aFeatureKind = theFeature->getKind();
-  // Point
-  if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
-    anAttrList.push_back(SketchPlugin_Point::COORD_ID());
-  // Line
-  else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Line::START_ID());
-    anAttrList.push_back(SketchPlugin_Line::END_ID());
-  }
-  // Circle
-  else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
-    anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
-  }
-  // Arc
-  else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) {
-    anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
-    anAttrList.push_back(SketchPlugin_Arc::START_ID());
-    anAttrList.push_back(SketchPlugin_Arc::END_ID());
-  }
-  /// \todo Other types of features should be implemented
-
-  // Check changing of feature's attributes (go through the groups and search usage of the attributes)
-  std::vector<std::string>::const_iterator anAttrIter;
-  for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) {
-    std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
-    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
-      if ((*aGroupIter)->isEmpty())
-        continue;
-      std::shared_ptr<ModelAPI_Attribute> anAttribute = std::dynamic_pointer_cast<
-          ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
-      (*aGroupIter)->updateEntityIfPossible(anAttribute);
-    }
-  }
-
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if (!(*aGroupIter)->isEmpty())
-      (*aGroupIter)->updateRelatedConstraintsFeature(theFeature);
+  std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+  for (; aGroupIt != myGroups.end(); aGroupIt++)
+    if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+      (*aGroupIt)->moveFeature(theFeature);
 }
 
 // ============================================================================
@@ -332,8 +304,8 @@ void SketchSolver_ConstraintManager::findGroups(
 {
   std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
 
-  SketchSolver_ConstraintGroup* anEmptyGroup = 0;  // appropriate empty group for specified constraint
-  std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+  SketchSolver_Group* anEmptyGroup = 0;  // appropriate empty group for specified constraint
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
       if (!(*aGroupIter)->isEmpty())
@@ -358,7 +330,7 @@ std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
   // Already verified workplanes
   std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
 
-  std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
     std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
     if (aVerified.find(aWP) != aVerified.end())
@@ -396,7 +368,7 @@ void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdat
     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
   }
 
-  std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
   for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
     if ((*aGroupIter)->resolveConstraints())
       needToUpdate = true;
index f5e148362bd448bb8e6020c258de1e6980c824d3..a2d7ffaffe580a08ca944a71938b56dfae64092d 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "SketchSolver.h"
 #include <SketchSolver_Solver.h>
-#include <SketchSolver_ConstraintGroup.h>
+#include <SketchSolver_Group.h>
 
 #include <Events_Listener.h>
 #include <SketchPlugin_Constraint.h>
@@ -67,7 +67,7 @@ class SketchSolver_ConstraintManager : public Events_Listener
    *  \return \c true if the workplane changed successfully
    *  \remark Type of theSketch is not verified inside
    */
-  bool changeWorkplane(std::shared_ptr<ModelAPI_CompositeFeature> theSketch);
+  bool changeWorkplane(CompositeFeaturePtr theSketch);
 
   /** \brief Removes a workplane from the manager.
    *         All groups based on such workplane will be removed too.
@@ -76,10 +76,10 @@ class SketchSolver_ConstraintManager : public Events_Listener
    */
   bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
 
-  /** \brief Updates entity which is neither workplane nor constraint
+  /** \brief Updates entity which is moved in GUI
    *  \param[in] theFeature entity to be updated
    */
-  void updateEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+  void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
 
   /** \brief Goes through the list of groups and solve the constraints
    *  \param theForceUpdate flushes the update event in any case: something changed or not
@@ -103,7 +103,7 @@ class SketchSolver_ConstraintManager : public Events_Listener
 
  private:
   static SketchSolver_ConstraintManager* _self;  ///< Self pointer to implement singleton functionality
-  std::vector<SketchSolver_ConstraintGroup*> myGroups;  ///< Groups of constraints
+  std::vector<SketchSolver_Group*> myGroups;  ///< Groups of constraints
   /// true if computation is performed and all "updates" are generated by this algo
   /// and needs no recomputation
   bool myIsComputed;
diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp
new file mode 100644 (file)
index 0000000..f3ded1d
--- /dev/null
@@ -0,0 +1,333 @@
+#include <SketchSolver_ConstraintMirror.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+
+
+void SketchSolver_ConstraintMirror::getAttributes(
+    Slvs_Entity& theMirrorLine,
+    std::vector<Slvs_Entity>& theBaseEntities,
+    std::vector<Slvs_Entity>& theMirrorEntities)
+{
+  DataPtr aData = myBaseConstraint->data();
+  AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+    return;
+  }
+  int aType = SLVS_E_UNKNOWN; // type of created entity
+  Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr);
+  if (anEntity == SLVS_E_UNKNOWN)
+    anEntity = changeEntity(aMirLineAttr, aType);
+  theMirrorLine = myStorage->getEntity(anEntity);
+
+  // Create SolveSpace entity for all features
+  AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+  AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+  myNumberOfObjects = aMirroredRefList->size();
+  if (!aBaseRefList || !aMirroredRefList) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
+    return;
+  }
+
+  std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+  std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+
+  FeaturePtr aFeature;
+  ResultConstructionPtr aRC;
+  for (int i = 0; i < 2; i++) {
+    std::list<ObjectPtr>::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin();
+    std::list<ObjectPtr>::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end();
+    std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
+    for ( ; anIter != aEndIter; anIter++) {
+      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
+      aFeature = aRC ? aRC->document()->feature(aRC) :
+        std::dynamic_pointer_cast<ModelAPI_Feature>(*anIter);
+      if (!aFeature)
+        continue;
+
+      anEntity = changeEntity(aFeature, aType);
+      aList->push_back(myStorage->getEntity(anEntity));
+    }
+  }
+
+  if (theBaseEntities.size() > theMirrorEntities.size())
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+}
+
+void SketchSolver_ConstraintMirror::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  Slvs_Entity aMirrorLine;
+  std::vector<Slvs_Entity> aBaseList;
+  std::vector<Slvs_Entity> aMirrorList;
+  getAttributes(aMirrorLine, aBaseList, aMirrorList);
+  if (!myErrorMsg.empty())
+    return;
+
+  if (aBaseList.size() != aMirrorList.size()) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
+    return;
+  }
+
+  Slvs_Constraint aConstraint;
+  // Get coordinates of mirror line points for speed up
+  double aStartEnd[4];
+  for (int i = 0; i < 2; i++) {
+    Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
+    for (int j = 0; j < 2; j++)
+      aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
+  }
+
+  std::vector<Slvs_Entity>::iterator aBaseIter = aBaseList.begin();
+  std::vector<Slvs_Entity>::iterator aMirrorIter = aMirrorList.begin();
+  for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) {
+    // Make aMirrorEnt parameters to be symmetric with aBaseEnt
+    makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd);
+
+    if (aBaseIter->type == SLVS_E_POINT_IN_2D) {
+      aConstraint = Slvs_MakeConstraint(
+          SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+          0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN);
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+    } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) {
+      for (int i = 0; i < 2; i++) {
+        aConstraint = Slvs_MakeConstraint(
+            SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+            aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN);
+        aConstraint.h = myStorage->addConstraint(aConstraint);
+        mySlvsConstraints.push_back(aConstraint.h);
+      }
+    } else if (aBaseIter->type == SLVS_E_CIRCLE) {
+      aConstraint = Slvs_MakeConstraint(
+          SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+          aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN);
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+      // Additional constraint for equal radii
+      Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+          SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(),
+          0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h);
+      anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr);
+      mySlvsConstraints.push_back(anEqRadConstr.h);
+    } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) {
+      // 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] = {
+          aBaseIter->point[1],
+          aBaseIter->point[2],
+          SLVS_E_UNKNOWN};
+      Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
+          aMirrorIter->point[2],
+          aMirrorIter->point[1],
+          SLVS_E_UNKNOWN};
+
+      Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
+      Slvs_hEntity aBothMiddlePoints[2];
+      for (int i = 0; i < 2; i++) {
+        double x, y;
+        calculateMiddlePoint(aBothArcs[i], 0.5, x, y);
+        Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x);
+        Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y);
+        aParamX.h = myStorage->addParameter(aParamX);
+        aParamY.h = myStorage->addParameter(aParamY);
+        Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(),
+            myGroup->getWorkplaneId(), aParamX.h, aParamY.h);
+        aBothMiddlePoints[i] = myStorage->addEntity(aPoint);
+        // additional constraint point-on-curve
+        Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
+            SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(),
+            0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN);
+        aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr);
+        mySlvsConstraints.push_back(aPonCircConstr.h);
+      }
+
+      aBaseArcPoints[2] = aBothMiddlePoints[0];
+      aMirrorArcPoints[2] = aBothMiddlePoints[1];
+      for (int ind = 0; ind < 3; ind++) {
+        Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+            SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
+            aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN);
+        aConstraint.h = myStorage->addConstraint(aConstraint);
+        mySlvsConstraints.push_back(aConstraint.h);
+      }
+    }
+  }
+
+  // Set the mirror line unchanged during constraint recalculation
+  for (int i = 0; i < 2; i++) {
+    aConstraint = Slvs_MakeConstraint(
+        SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
+        aMirrorLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    aConstraint.h = myStorage->addConstraint(aConstraint);
+    mySlvsConstraints.push_back(aConstraint.h);
+  }
+}
+
+
+void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (!theConstraint || theConstraint == myBaseConstraint) {
+    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+        myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+    if (aMirroredRefList->size() != myNumberOfObjects) {
+      remove(myBaseConstraint);
+      process();
+    }
+  }
+  SketchSolver_Constraint::update();
+}
+
+bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  bool isFullyRemoved = true;
+  std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++)
+   isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+  mySlvsConstraints.clear();
+
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  return true;
+}
+
+void SketchSolver_ConstraintMirror::makeMirrorEntity(
+    const Slvs_Entity& theBase,
+    const Slvs_Entity& theMirror,
+    const double theMirrorLine[]) const
+{
+  Slvs_hEntity aBasePoint[4];
+  Slvs_hEntity aMirrorPoint[4];
+  for (int i = 0; i < 4; i++) {
+    aBasePoint[i] = theBase.point[i];
+    aMirrorPoint[i] = theMirror.point[i];
+  }
+  if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
+    Slvs_hEntity aTmp = aMirrorPoint[2];
+    aMirrorPoint[2] = aMirrorPoint[1];
+    aMirrorPoint[1] = aTmp;
+  }
+  if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) {
+    aBasePoint[0] = theBase.h;
+    aMirrorPoint[0] = theMirror.h;
+  }
+
+  // Mirror line parameters
+  std::shared_ptr<GeomAPI_XY> aLinePoints[2];
+  for (int i = 0; i < 2; i++)
+    aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
+        new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1]));
+  // direction of a mirror line
+  std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
+    new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
+  // orthogonal direction
+  aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
+
+  for (int i = 0; i < 4; i++) {
+    if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
+      continue;
+    Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]);
+    double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val;
+    double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val;
+    std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aBaseX, aBaseY));
+
+    std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
+        new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
+    double aDist = aVec->dot(aDir->xy());
+    aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
+
+    Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]);
+    Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x());
+    myStorage->updateParameter(aParam);
+    aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y());
+    myStorage->updateParameter(aParam);
+  }
+}
+
+void SketchSolver_ConstraintMirror::adjustConstraint()
+{
+  // Search mirror between middle points on the arcs and recompute their coordinates
+  std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
+  if (aPonCirc.empty())
+    return;
+
+  AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+  if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+    myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+    return;
+  }
+  ResultConstructionPtr aRC =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
+  FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+    std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
+  std::map<FeaturePtr, Slvs_hEntity>::iterator aMirLineIter = myFeatureMap.find(aFeature);
+  if (aMirLineIter == myFeatureMap.end())
+    return;
+  Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
+
+  double aStartEnd[4];
+  for (int i = 0; i < 2; i++) {
+    Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
+    for (int j = 0; j < 2; j++)
+      aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
+  }
+
+  Slvs_Constraint aMirror;
+  std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+  for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
+    aMirror = myStorage->getConstraint(*aConstrIter);
+    if (aMirror.type != SLVS_C_SYMMETRIC_LINE)
+      continue;
+    Slvs_Constraint aPonCircA, aPonCircB;
+    aPonCircA.h = SLVS_E_UNKNOWN;
+    aPonCircB.h = SLVS_E_UNKNOWN;
+    std::list<Slvs_Constraint>::iterator aPtIter = aPonCirc.begin();
+    for (; aPtIter != aPonCirc.end(); aPtIter++) {
+      if (aMirror.ptA == aPtIter->ptA)
+        aPonCircA = *aPtIter;
+      if (aMirror.ptB == aPtIter->ptA)
+        aPonCircB = *aPtIter;
+    }
+    if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
+      continue;
+
+    // Calculate middle point for base arc and mirrored point on mirror arc
+    Slvs_Entity aBaseArc = myStorage->getEntity(aPonCircA.entityA);
+    Slvs_Entity aBasePoint = myStorage->getEntity(aPonCircA.ptA);
+    Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]);
+    Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]);
+    calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val);
+    myStorage->updateParameter(aParamX);
+    myStorage->updateParameter(aParamY);
+    Slvs_Entity aMirrorPoint = myStorage->getEntity(aPonCircB.ptA);
+    makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd);
+  }
+}
diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.h b/src/SketchSolver/SketchSolver_ConstraintMirror.h
new file mode 100644 (file)
index 0000000..eb3af1f
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintMirror.h
+// Created: 1 Apr 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintMirror_H_
+#define SketchSolver_ConstraintMirror_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintMirror
+ *  \ingroup Plugins
+ *  \brief   Convert fillet constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintMirror : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint),
+      myNumberOfObjects(0)
+  {}
+
+  virtual int getType() const
+  { return SLVS_C_SYMMETRIC_LINE; }
+
+  /// \brief Update constraint
+  virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+  { /* do nothing here */ }
+
+  /// \brief Generate list of entities of mirror constraint
+  /// \param[out] theMirrorLine     entity corresponding to mirror line
+  /// \param[out] theBaseEntities   list of entities to mirror
+  /// \param[out] theMirrorEntities list of mirrored entities
+  void getAttributes(Slvs_Entity& theMirrorLine,
+                     std::vector<Slvs_Entity>& theBaseEntities,
+                     std::vector<Slvs_Entity>& theMirrorEntities);
+
+  /// \brief This method is used in derived objects to check consistence of constraint.
+  ///        E.g. the distance between line and point may be signed.
+  virtual void adjustConstraint();
+
+private:
+  /// \brief Change parameters of entities to be symmetric relative a line,
+  ///        given by array of parameters (coordinates of first and last points)
+  void makeMirrorEntity(const Slvs_Entity& theBase,
+                        const Slvs_Entity& theMirror,
+                        const double theMirrorLine[]) const;
+
+private:
+  size_t myNumberOfObjects; ///< number of previously mirrored objects
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp
new file mode 100644 (file)
index 0000000..a1deb96
--- /dev/null
@@ -0,0 +1,243 @@
+#include <SketchSolver_ConstraintRigid.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Group.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_ConstraintRigid.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
+  : SketchSolver_Constraint(),
+    myBaseFeature(theFeature)
+{
+  process();
+}
+
+void SketchSolver_ConstraintRigid::process()
+{
+  cleanErrorMsg();
+  if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntities;
+  getAttributes(aValue, anEntities);
+  if (!myErrorMsg.empty())
+    return;
+
+  Slvs_Constraint aConstraint;
+  std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
+  bool isEmpty = aConstrIter == mySlvsConstraints.end();
+
+  // Check the fixed entity is an arc
+  if (isEmpty) {
+    if (!myFeatureMap.empty() && myFeatureMap.begin()->first->getKind() == SketchPlugin_Arc::ID()) {
+      Slvs_Entity anArc = myStorage->getEntity(myFeatureMap.begin()->second);
+      fixArc(anArc);
+      return;
+    }
+  }
+
+  std::vector<Slvs_hEntity>::const_iterator anEntIter = anEntities.begin();
+  for (; anEntIter != anEntities.end(); anEntIter++) {
+    if (*anEntIter == SLVS_E_UNKNOWN)
+      continue;
+    Slvs_hConstraint aConstrID = myStorage->isPointFixed(*anEntIter);
+    bool isForceUpdate = (aConstrID != SLVS_E_UNKNOWN && !myBaseConstraint);
+    if (isEmpty && !isForceUpdate) { // create new constraint
+      if (aConstrID != SLVS_E_UNKNOWN)
+        continue; // the coincident point is already fixed
+      aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+          aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+      aConstraint.h = myStorage->addConstraint(aConstraint);
+      mySlvsConstraints.push_back(aConstraint.h);
+      if (!myBaseConstraint)
+        myStorage->addTemporaryConstraint(aConstraint.h);
+    } else { // update already existent constraint
+      if (aConstrID == SLVS_E_UNKNOWN || myBaseConstraint)
+        aConstrID = *aConstrIter;
+      aConstraint = myStorage->getConstraint(aConstrID);
+      aConstraint.ptA = *anEntIter;
+      myStorage->addConstraint(aConstraint);
+      if (!myBaseConstraint)
+        myStorage->addTemporaryConstraint(aConstraint.h);
+      if (!isEmpty) {
+        aConstrIter++;
+        isEmpty = aConstrIter == mySlvsConstraints.end();
+      }
+    }
+  }
+
+  if (!myFeatureMap.empty() && myFeatureMap.begin()->first->getKind() == SketchPlugin_Circle::ID()) {
+    // Fix radius of a circle
+    AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+        myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
+    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, myGroup->getWorkplaneId(),
+      aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
+    aConstraint.h = myStorage->addConstraint(aConstraint);
+    mySlvsConstraints.push_back(aConstraint.h);
+    if (!myBaseConstraint)
+      myStorage->addTemporaryConstraint(aConstraint.h);
+  }
+}
+
+
+void SketchSolver_ConstraintRigid::getAttributes(
+    double& theValue,
+    std::vector<Slvs_hEntity>& theAttributes)
+{
+  theValue = 0.0;
+  int aType = SLVS_E_UNKNOWN; // type of created entity
+  Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
+  if (myBaseConstraint) {
+    // Get the attribute of constraint
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+    if (!aRefAttr || !aRefAttr->isInitialized()) {
+      myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+      return;
+    }
+    anEntityID = myGroup->getAttributeId(aRefAttr);
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(aRefAttr, aType);
+  } else {
+    anEntityID = myGroup->getFeatureId(myBaseFeature);
+    if (anEntityID == SLVS_E_UNKNOWN)
+      anEntityID = changeEntity(myBaseFeature, aType);
+    else
+      myFeatureMap[myBaseFeature] = anEntityID;
+  }
+
+  // Check the entity is complex
+  Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
+  if (anEntity.point[0] != SLVS_E_UNKNOWN) {
+    for (int i = 0; i < 4 && anEntity.point[i]; i++)
+      theAttributes.push_back(anEntity.point[i]);
+  } else // simple entity
+    theAttributes.push_back(anEntityID);
+}
+
+void SketchSolver_ConstraintRigid::adjustConstraint()
+{
+  if (myFeatureMap.empty() || (
+      myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() && 
+      myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID()))
+    return;
+  FeaturePtr aFeature = myFeatureMap.begin()->first;
+
+  // Search radius constraints and update them
+  Slvs_Constraint aConstraint;
+  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++) {
+    aConstraint = myStorage->getConstraint(*aCIter);
+    if (aConstraint.type != SLVS_C_DIAMETER)
+      continue;
+    double aRadius = 0.0;
+    if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
+      std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+      std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+      aRadius = aCenter->distance(aStart);
+    } else {
+      aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+          aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value();
+    }
+
+    aConstraint.valA = aRadius * 2.0;
+    *aCIter = myStorage->updateConstraint(aConstraint);
+  }
+}
+
+
+bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
+{
+  cleanErrorMsg();
+  if (theConstraint && theConstraint != myBaseConstraint)
+    return false;
+  bool isFullyRemoved = true;
+  std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
+  for (; aCIter != mySlvsConstraints.end(); aCIter++)
+    isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
+
+  if (isFullyRemoved) {
+    myFeatureMap.clear();
+    myAttributeMap.clear();
+    myValueMap.clear();
+  } else
+    cleanRemovedEntities();
+  return true;
+}
+
+
+void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
+{
+  Slvs_Constraint aConstraint;
+  Slvs_hConstraint aConstrID = myStorage->isPointFixed(theArc.point[0]);
+  int aPointsToFix = 2; // number of fixed points for the arc
+  if (aConstrID != SLVS_E_UNKNOWN)
+    aPointsToFix--;
+
+  // Radius of the arc
+  FeaturePtr aFeature = myFeatureMap.begin()->first;
+  std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+  std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+  double aRadius = aCenter->distance(aStart);
+
+  // Update end point of the arc to be on a curve
+  std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+  double aDistance = anEnd->distance(aCenter);
+  std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
+  if (aDistance < tolerance)
+    aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
+  else
+    aDir = aDir->multiplied(aRadius / aDistance);
+  double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
+  Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
+  for (int i = 0; i < 2; i++) {
+    Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
+    aParam.val = xy[i];
+    myStorage->updateParameter(aParam);
+  }
+
+  for (int i = 1; aPointsToFix > 0; i++, aPointsToFix--) {
+    aConstrID = myStorage->isPointFixed(theArc.point[i]);
+    if (aConstrID != SLVS_E_UNKNOWN)
+      continue; // the coincident point is already fixed
+    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
+        0.0, theArc.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    aConstraint.h = myStorage->addConstraint(aConstraint);
+    mySlvsConstraints.push_back(aConstraint.h);
+    if (!myBaseConstraint)
+      myStorage->addTemporaryConstraint(aConstraint.h);
+  }
+
+  // Fix radius of the arc
+  bool isExists = false;
+  std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
+  std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
+  for (; anIt != aDiamConstraints.end() && !isExists; anIt)
+    if (anIt->entityA == myFeatureMap.begin()->second)
+      isExists = true;
+  if (!isExists) {
+    aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, myGroup->getWorkplaneId(),
+      aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
+    aConstraint.h = myStorage->addConstraint(aConstraint);
+    mySlvsConstraints.push_back(aConstraint.h);
+    if (!myBaseConstraint)
+      myStorage->addTemporaryConstraint(aConstraint.h);
+  }
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h
new file mode 100644 (file)
index 0000000..dd14877
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintRigid.h
+// Created: 30 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintRigid_H_
+#define SketchSolver_ConstraintRigid_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintRigid
+ *  \ingroup Plugins
+ *  \brief   Stores data of Rigid (Fixed) constraint
+ *
+ *  Rigid constraint may have NULL basic SketchPlugin constraint,
+ *  because the Rigid constraint may be temporary for correct moving of objects
+ */
+class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
+{
+public:
+  /// Creates constraint to manage the given constraint from plugin
+  SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
+    : SketchSolver_Constraint(theConstraint)
+  {}
+  /// Creates temporary constraint based on feature
+  SketchSolver_ConstraintRigid(FeaturePtr theFeature);
+
+  /// \brief Tries to remove constraint
+  /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+  virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+
+  /// \brief Returns the type of constraint
+  virtual int getType() const
+  { return SLVS_C_WHERE_DRAGGED; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+  /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+  /// \param[out] theValue      numerical characteristic of constraint (e.g. distance)
+  /// \param[out] theAttributes list of attributes to be filled
+  virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+
+  /// \brief This method is used in derived objects to check consistence of constraint.
+  ///        E.g. the distance between line and point may be signed.
+  virtual void adjustConstraint();
+
+private:
+  /// \brief The arc is fixed differently to avoid SolveSpace problems (overconstraint)
+  ///
+  /// There will be fixed start and end points and the radius of the arc.
+  void fixArc(const Slvs_Entity& theArc);
+
+protected:
+  FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp
new file mode 100644 (file)
index 0000000..37b59fa
--- /dev/null
@@ -0,0 +1,84 @@
+#include <SketchSolver_ConstraintTangent.h>
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Error.h>
+
+
+void SketchSolver_ConstraintTangent::process()
+{
+  cleanErrorMsg();
+  if (!myBaseConstraint || !myStorage || myGroup == 0) {
+    /// TODO: Put error message here
+    return;
+  }
+  if (!mySlvsConstraints.empty()) // some data is changed, update constraint
+    update(myBaseConstraint);
+
+  double aValue;
+  std::vector<Slvs_hEntity> anEntID;
+  getAttributes(aValue, anEntID);
+  if (!myErrorMsg.empty())
+    return;
+  // Check the quantity of entities of each type and their order (arcs first)
+  int aNbLines = 0;
+  int aNbArcs = 0;
+  Slvs_Entity anEntities[2];
+  myType = SLVS_C_CURVE_CURVE_TANGENT;
+  std::vector<Slvs_hEntity>::iterator anEntIter = anEntID.begin();
+  for (; anEntIter != anEntID.end(); anEntIter++) {
+    Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
+    if (anEnt.type == SLVS_E_LINE_SEGMENT) {
+      if (aNbLines == 0)
+        anEntities[1 + aNbLines] = anEnt;
+      aNbLines++;
+      myType = SLVS_C_ARC_LINE_TANGENT;
+    }
+    else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
+      if (aNbArcs < 2)
+        anEntities[aNbArcs] = anEnt;
+      aNbArcs++;
+    }
+  }
+
+  if (aNbLines + aNbArcs != 2) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+    return;
+  } else if (aNbArcs < 1) {
+    myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
+    return;
+  }
+
+  // It is necessary to identify which points of entities are coincident
+  int aSlvsOtherFlag = 0;
+  int aSlvsOther2Flag = 0;
+  // Obtain start and end points of entities
+  Slvs_hEntity aPointsToFind[4];
+  for (int i = 0; i < 2; i++) {
+    int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
+    aPointsToFind[2*i]  = anEntities[i].point[aShift];
+    aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
+  }
+  // Search coincident points
+  bool isPointFound = false;
+  for (int i = 0; i < 2 && !isPointFound; i++)
+    for (int j = 2; j < 4 && !isPointFound; j++)
+      if (myStorage->isCoincident(aPointsToFind[i], aPointsToFind[j])) {
+        aSlvsOtherFlag = i;
+        aSlvsOther2Flag = j - 2;
+        isPointFound = true;
+      }
+  if (!isPointFound) {
+    // There is no coincident points between tangential objects. Generate error message
+    myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+    return;
+  }
+
+  Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
+      getType(), myGroup->getWorkplaneId(), aValue,
+      SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h);
+  aConstraint.other = aSlvsOtherFlag;
+  aConstraint.other2 = aSlvsOther2Flag;
+  aConstraint.h = myStorage->addConstraint(aConstraint);
+  mySlvsConstraints.push_back(aConstraint.h);
+  adjustConstraint();
+}
+
diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h
new file mode 100644 (file)
index 0000000..7f7e30d
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_ConstraintTangent.h
+// Created: 1 Apr 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintTangent_H_
+#define SketchSolver_ConstraintTangent_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class   SketchSolver_ConstraintTangent
+ *  \ingroup Plugins
+ *  \brief   Convert tangency constraint to SolveSpace structure
+ */
+class SketchSolver_ConstraintTangent : public SketchSolver_Constraint
+{
+public:
+  SketchSolver_ConstraintTangent(ConstraintPtr theConstraint) :
+      SketchSolver_Constraint(theConstraint)
+  {}
+
+  virtual int getType() const
+  { return myType; }
+
+protected:
+  /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+  virtual void process();
+
+private:
+  int myType; ///< type of constraint (applicable: SLVS_C_ARC_LINE_TANGENT, SLVS_C_CURVE_CURVE_TANGENT)
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_Error.h b/src/SketchSolver/SketchSolver_Error.h
new file mode 100644 (file)
index 0000000..3623354
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Error.h
+// Created: 29 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Error_H_
+#define SketchSolver_Error_H_
+
+#include <string>
+
+/** \class SketchSolver_Error
+ *  \ingroup Plugins
+ *  \brief Collects all sketch solver error' codes
+ *         as inline static functions
+ */
+class SketchSolver_Error
+{
+ public:
+  /// The value parameter for the constraint
+  inline static const std::string& CONSTRAINTS()
+  {
+    static const std::string MY_ERROR_VALUE("Conflicting constraints");
+    return MY_ERROR_VALUE;
+  }
+  /// Constraints should use objects instead of features as attributes
+  inline static const std::string& NEED_OBJECT_NOT_FEATURE()
+  {
+    static const std::string MY_ERROR_VALUE("Constraint should be based on object instead of feature");
+    return MY_ERROR_VALUE;
+  }
+  /// The entities need to have shared point, but they have not
+  inline static const std::string& NO_COINCIDENT_POINTS()
+  {
+    static const std::string MY_ERROR_VALUE("Objects should have coincident point");
+    return MY_ERROR_VALUE;
+  }
+  /// Attribute of a feature is not initialized
+  inline static const std::string& NOT_INITIALIZED()
+  {
+    static const std::string MY_ERROR_VALUE("Attribute is not initialized");
+    return MY_ERROR_VALUE;
+  }
+  /// Constraint has wrong attributes
+  inline static const std::string& INCORRECT_ATTRIBUTE()
+  {
+    static const std::string MY_ERROR_VALUE("Incorrect attribute");
+    return MY_ERROR_VALUE;
+  }
+  /// Tangency constraint has wrong attributes
+  inline static const std::string& INCORRECT_TANGENCY_ATTRIBUTE()
+  {
+    static const std::string MY_ERROR_VALUE("An arc should be an attribute of tangency constraint");
+    return MY_ERROR_VALUE;
+  }
+  /// Mirror constraint has wrong attributes
+  inline static const std::string& INCORRECT_MIRROR_ATTRIBUTE()
+  {
+    static const std::string MY_ERROR_VALUE("Mirror constraint has wrong attributes");
+    return MY_ERROR_VALUE;
+  }
+};
+
+#endif
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp
new file mode 100644 (file)
index 0000000..610993a
--- /dev/null
@@ -0,0 +1,385 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_FeatureStorage.cpp
+// Created: 23 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SketchSolver_FeatureStorage.h>
+
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_ResultConstruction.h>
+
+void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
+{
+  std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject()) {
+        changeAttribute(aRefAttr->attr(), theConstraint);
+        continue;
+      }
+      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+          aRefAttr->object());
+      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+      if (aFeature)
+        changeFeature(aFeature, theConstraint);
+      continue;
+    }
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+    if (aRefList) {
+      std::list<ObjectPtr> aList = aRefList->list();
+      std::list<ObjectPtr>::iterator aListIter = aList.begin();
+      for (; aListIter != aList.end(); aListIter++) {
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            *aListIter);
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+        if (aFeature)
+          changeFeature(aFeature, theConstraint);
+      }
+      continue;
+    }
+    changeAttribute(*anIter, theConstraint);
+  }
+  myConstraints.insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
+{
+  DataPtr aData = theConstraint->data();
+  if (aData) { // Constraint has data. Iterate through its attributes and remove them
+    std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+    std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+    for (; anIter != anAttributes.end(); anIter++) {
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+      if (aRefAttr) {
+        if (!aRefAttr->isObject()) {
+          removeAttribute(aRefAttr->attr(), theConstraint);
+          continue;
+        }
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            aRefAttr->object());
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+        if (aFeature)
+          removeFeature(aFeature, theConstraint);
+        continue;
+      }
+      AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+      if (aRefList) {
+        std::list<ObjectPtr> aList = aRefList->list();
+        std::list<ObjectPtr>::iterator aListIter = aList.begin();
+        for (; aListIter != aList.end(); aListIter++) {
+          ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+              *aListIter);
+          FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+              std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+          if (aFeature)
+            removeFeature(aFeature, theConstraint);
+        }
+        continue;
+      }
+      removeAttribute(*anIter, theConstraint);
+    }
+  } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
+    std::set<ConstraintPtr>::iterator aCIter;
+    MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
+    while (aFeatIter != myFeatures.end()) {
+      aCIter = aFeatIter->second.find(theConstraint);
+      if (aCIter != aFeatIter->second.end()) {
+        aFeatIter->second.erase(aCIter);
+        if (aFeatIter->second.empty()) {
+          MapFeatureConstraint::iterator aTmpIter = aFeatIter; // stores iterator for the next element, while the current is deleting
+          aTmpIter++;
+          myFeatures.erase(aFeatIter);
+          aFeatIter = aTmpIter;
+          continue;
+        }
+      }
+      aFeatIter++;
+    }
+    std::set<FeaturePtr>::iterator aFIter;
+    MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
+    while (anAttrIter != myAttributes.end()) {
+      aFIter = anAttrIter->second.find(theConstraint);
+      if (aFIter != anAttrIter->second.end()) {
+        anAttrIter->second.erase(aFIter);
+        if (anAttrIter->second.empty()) {
+          MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
+          aTmpIter++;
+          myAttributes.erase(anAttrIter);
+          anAttrIter = aTmpIter;
+          continue;
+        }
+      }
+      anAttrIter++;
+    }
+  }
+  myConstraints.erase(theConstraint);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
+{
+  if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
+    return true;
+
+  DataPtr aData = theConstraint->data();
+  if (!aData)
+    return false;
+
+  std::list<AttributePtr> anAttributes = aData->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject()) {
+        if (isInteract(aRefAttr->attr()))
+          return true;
+        continue;
+      }
+      ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+          aRefAttr->object());
+      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+      if (aFeature)
+        if (isInteract(aFeature))
+          return true;
+      continue;
+    }
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
+    if (aRefList) {
+      std::list<ObjectPtr> aList = aRefList->list();
+      std::list<ObjectPtr>::iterator aListIter = aList.begin();
+      for (; aListIter != aList.end(); aListIter++) {
+        ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+            *aListIter);
+        FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+            std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
+        if (aFeature)
+          if (isInteract(aFeature))
+            return true;
+      }
+      continue;
+    }
+    if (isInteract(*anIter))
+      return true;
+  }
+  return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
+{
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        changeAttribute(aRefAttr->attr(), theFeature);
+      continue;
+    }
+    changeAttribute(*anIter, theFeature);
+  }
+  if (myFeatures.find(theFeature) == myFeatures.end())
+    myFeatures[theFeature] = std::set<ConstraintPtr>();
+}
+
+void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+  // Change all attributes of the feature
+  changeFeature(theFeature);
+  // Add back reference feature to constraint
+  myFeatures[theFeature].insert(theConstraint);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
+{
+  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    return; // no such feature
+
+  std::set<ConstraintPtr> aConstraints = aFeatIter->second;
+  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+  for (; aCIter != aConstraints.end(); aCIter++)
+    removeFeature(theFeature, *aCIter);
+}
+
+void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
+{
+  MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    return; // no such feature
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        removeAttribute(aRefAttr->attr(), theFeature);
+      continue;
+    }
+    removeAttribute(*anIter, theFeature);
+  }
+
+  aFeatIter->second.erase(theConstraint);
+  if (aFeatIter->second.empty())
+    myFeatures.erase(aFeatIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
+{
+  if (myFeatures.find(theFeature) != myFeatures.end())
+    return true;
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::iterator anIter = anAttributes.begin();
+  for (; anIter != anAttributes.end(); anIter++) {
+    AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
+    if (aRefAttr) {
+      if (!aRefAttr->isObject())
+        if (isInteract(aRefAttr->attr()))
+          return true;
+      continue;
+    }
+    if (isInteract(*anIter))
+      return true;
+  }
+  return false;
+}
+
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
+{
+  if (myAttributes.find(theAttribute) == myAttributes.end())
+    myAttributes[theAttribute] = std::set<FeaturePtr>();
+}
+
+void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter == myAttributes.end()) {
+    std::set<FeaturePtr> aFeatures;
+    aFeatures.insert(theFeature);
+    myAttributes[theAttribute] = aFeatures;
+    return;
+  }
+  anAttrIter->second.insert(theFeature);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter == myAttributes.end())
+    return;
+
+  std::set<FeaturePtr> aFeatures = anAttrIter->second;
+  std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
+  for (; aFeatIter != aFeatures.end(); aFeatIter++)
+    removeAttribute(theAttribute, *aFeatIter);
+}
+
+void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
+{
+  MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
+  if (anAttrIter != myAttributes.end())
+    return; // no such attribute
+
+  anAttrIter->second.erase(theFeature);
+  if (anAttrIter->second.empty())
+    myAttributes.erase(anAttrIter);
+}
+
+bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
+{
+  return myAttributes.find(theAttribute) != myAttributes.end();
+}
+
+
+bool SketchSolver_FeatureStorage::isConsistent() const
+{
+  // Check the constraints are valid
+  std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
+      return false;
+  // Check the features are valid
+  MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+  for (; aFIter != myFeatures.end(); aFIter++)
+    if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+      return false;
+  return true;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
+{
+  std::set<ConstraintPtr> aResult;
+  MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
+  if (aFeatIter != myFeatures.end())
+    aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+
+  std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+  std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
+  for (; anAttrIter != anAttributes.end(); anAttrIter++) {
+    MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
+    if (anIt == myAttributes.end())
+      continue;
+    std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+    for (; aFIter != anIt->second.end(); aFIter++) {
+      aFeatIter = myFeatures.find(*aFIter);
+      if (aFeatIter != myFeatures.end())
+        aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+      else {
+        ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+        if (aConstraint)
+          aResult.insert(aConstraint);
+      }
+    }
+  }
+  return aResult;
+}
+
+std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
+{
+  std::set<ConstraintPtr> aResult;
+  MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
+  if (anIt == myAttributes.end())
+    return aResult;
+  std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
+  MapFeatureConstraint::const_iterator aFeatIter;
+  for (; aFIter != anIt->second.end(); aFIter++) {
+    aFeatIter = myFeatures.find(*aFIter);
+    if (aFeatIter != myFeatures.end())
+      aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
+    else {
+      ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
+      if (aConstraint)
+        aResult.insert(aConstraint);
+    }
+  }
+  return aResult;
+}
+
+void SketchSolver_FeatureStorage::blockEvents(bool isBlocked) const
+{
+  std::set<ConstraintPtr>::iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if ((*aCIter)->data() && (*aCIter)->data()->isValid())
+      (*aCIter)->data()->blockSendAttributeUpdated(isBlocked);
+
+  MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
+  for (; aFIter != myFeatures.end(); aFIter++)
+    if (aFIter->first->data() && aFIter->first->data()->isValid())
+      aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
+
+  MapAttributeFeature::const_iterator anAtIter = myAttributes.begin();
+  for (; anAtIter != myAttributes.end(); anAtIter++)
+    if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
+        anAtIter->first->owner()->data()->isValid())
+      anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
+}
diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.h b/src/SketchSolver/SketchSolver_FeatureStorage.h
new file mode 100644 (file)
index 0000000..2cb36ba
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_FeatureStorage.h
+// Created: 23 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_FeatureStorage_H_
+#define SketchSolver_FeatureStorage_H_
+
+#include <SketchSolver.h>
+#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <set>
+#include <map>
+
+typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
+typedef std::map<AttributePtr, std::set<FeaturePtr> >  MapAttributeFeature;
+
+/** \class   SketchSolver_FeatureStorage
+ *  \ingroup Plugins
+ *  \brief   Collects information about SketchPlugin constraints used in specific group
+ */
+class SketchSolver_FeatureStorage
+{
+public:
+  SketchSolver_FeatureStorage() {}
+
+  /// \brief Adds or changes a constraint and all features it uses in the storage
+  void changeConstraint(ConstraintPtr theConstraint);
+  /// \brief Removes a constraint and all its features not used by other constraints
+  void removeConstraint(ConstraintPtr theConstraint);
+  /// \brief Verifies a constraint is used in the current storage
+  bool isInteract(ConstraintPtr theConstraint) const;
+
+  /// \brief Adds or changes a feature in the storage
+  void changeFeature(FeaturePtr theFeature);
+  /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
+  void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+  /// \brief Removes a feature
+  void removeFeature(FeaturePtr theFeature);
+  /// \brief Removes a feature according to a given constraint
+  void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
+  /// \brief Verifies a feature is used in the current storage
+  bool isInteract(FeaturePtr theFeature) const;
+
+  /// \brief Adds or changes an attribute in the storage
+  void changeAttribute(AttributePtr theAttribute);
+  /// \brief Adds or changes a attribute in the storage.
+  ///        The attribute is used in specified feature or constraint (theFeature)
+  void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+  /// \brief Removes an attribute
+  void removeAttribute(AttributePtr theAttribute);
+  /// \brief Removes an attribute according to a given feature
+  void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
+  /// \brief Verifies an attribute is used in the current storage
+  bool isInteract(AttributePtr theAttribute) const;
+
+  /// \brief Check the features is not removed
+  bool isConsistent() const;
+
+  /// \brief Prepares list of constraints, which using specified feature or its attributes
+  std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
+  /// \brief Prepares list of constraints, which using specified attribute
+  std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
+
+  /// \brief Block/unblock events of changing attributes of the features
+  void blockEvents(bool isBlocked) const;
+
+private:
+  std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
+  MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
+  MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
+};
+
+typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
+
+#endif // SketchSolver_FeatureStorage_H_
diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp
new file mode 100644 (file)
index 0000000..2c6d8f5
--- /dev/null
@@ -0,0 +1,529 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Group.cpp
+// Created: 27 May 2014
+// Author:  Artem ZHIDKOV
+
+#include "SketchSolver_Group.h"
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_ConstraintCoincidence.h>
+#include <SketchSolver_Error.h>
+
+#include <Events_Error.h>
+#include <Events_Loop.h>
+#include <GeomAPI_XY.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_Feature.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <math.h>
+#include <assert.h>
+
+
+/// \brief This class is used to give unique index to the groups
+class GroupIndexer
+{
+public:
+  /// \brief Return vacant index
+  static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+  /// \brief Removes the index
+  static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+    if (myGroupIndex == theIndex)
+      myGroupIndex--;
+  }
+
+private:
+  GroupIndexer() {};
+
+  static Slvs_hGroup myGroupIndex; ///< index of the group
+};
+
+Slvs_hGroup GroupIndexer::myGroupIndex = 0;
+
+
+
+// ========================================================
+// =========  SketchSolver_Group  ===============
+// ========================================================
+
+SketchSolver_Group::SketchSolver_Group(
+    std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
+    : myID(GroupIndexer::NEW_GROUP())
+{
+  // Initialize workplane
+  myWorkplaneID = SLVS_E_UNKNOWN;
+#ifndef NDEBUG
+  assert(addWorkplane(theWorkplane));
+#else
+  addWorkplane(theWorkplane);
+#endif
+}
+
+SketchSolver_Group::~SketchSolver_Group()
+{
+  myConstraints.clear();
+  GroupIndexer::REMOVE_GROUP(myID);
+}
+
+// ============================================================================
+//  Function: isBaseWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  verify the group is based on the given workplane
+// ============================================================================
+bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
+{
+  return theWorkplane == mySketch;
+}
+
+// ============================================================================
+//  Function: isInteract
+//  Class:    SketchSolver_Group
+//  Purpose:  verify are there any entities in the group used by given constraint
+// ============================================================================
+bool SketchSolver_Group::isInteract(
+    std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+  // Empty group interacts with everything
+  if (isEmpty()) return true;
+  ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+  if (aConstraint)
+    return myFeatureStorage->isInteract(aConstraint);
+  return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
+}
+
+// ============================================================================
+//  Function: getFeatureId
+//  Class:    SketchSolver_Group
+//  Purpose:  Find the identifier of the feature, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!myFeatureStorage)
+    return aResult;
+  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theFeature);
+  if (aConstraints.empty())
+    return aResult;
+  std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
+  for (; aConstrIter != aConstraints.end(); aConstrIter++) {
+    ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
+    if (aCIter == myConstraints.end())
+      continue;
+    aResult = aCIter->second->getId(theFeature);
+    if (aResult != SLVS_E_UNKNOWN)
+      return aResult;
+  }
+  return SLVS_E_UNKNOWN;
+}
+
+// ============================================================================
+//  Function: getAttributeId
+//  Class:    SketchSolver_Group
+//  Purpose:  Find the identifier of the attribute, if it already exists in the group
+// ============================================================================
+Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
+{
+  Slvs_hEntity aResult = SLVS_E_UNKNOWN;
+  if (!myFeatureStorage)
+    return aResult;
+  std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(theAttribute);
+  if (aConstraints.empty())
+    return aResult;
+  std::set<ConstraintPtr>::iterator aConstrIter = aConstraints.begin();
+  for (; aConstrIter != aConstraints.end(); aConstrIter++) {
+    ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter);
+    if (aCIter == myConstraints.end())
+      continue;
+    aResult = aCIter->second->getId(theAttribute);
+    if (aResult != SLVS_E_UNKNOWN)
+      return aResult;
+  }
+  return SLVS_E_UNKNOWN;
+}
+
+// ============================================================================
+//  Function: changeConstraint
+//  Class:    SketchSolver_Group
+//  Purpose:  create/update the constraint in the group
+// ============================================================================
+bool SketchSolver_Group::changeConstraint(
+    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+  // There is no workplane yet, something wrong
+  if (myWorkplaneID == SLVS_E_UNKNOWN)
+    return false;
+
+  if (!theConstraint)
+    return false;
+
+  if (myConstraints.find(theConstraint) == myConstraints.end()) {
+    // Add constraint to the current group
+    SolverConstraintPtr aConstraint =
+        SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+    if (!aConstraint)
+      return false;
+    aConstraint->setGroup(this);
+    aConstraint->setStorage(myStorage);
+    if (!aConstraint->error().empty()) {
+      if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
+        return false; // some attribute are not initialized yet, don't show message
+      Events_Error::send(aConstraint->error(), this);
+    }
+
+    // Additional verification of coincidence of several points
+    if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+      ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+      for (; aCIter != myConstraints.end(); aCIter++) {
+        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
+          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
+        if (!aCoincidence)
+          continue;
+        std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
+          std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
+        if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
+          aCoincidence->attach(aCoinc2);
+          aConstraint = aCoincidence;
+        }
+      }
+    }
+    myConstraints[theConstraint] = aConstraint;
+  }
+  else
+    myConstraints[theConstraint]->update();
+
+  // Fix base features for fillet
+  if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
+    std::list<AttributePtr> anAttrList =
+        theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+    std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
+    for (; anAttrIter != anAttrList.end(); anAttrIter++) {
+      AttributeRefAttrPtr aRefAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+      if (!aRefAttr || !aRefAttr->isObject())
+        continue;
+      FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+      SolverConstraintPtr aConstraint =
+          SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+      if (!aConstraint)
+        continue;
+      aConstraint->setGroup(this);
+      aConstraint->setStorage(myStorage);
+      myTempConstraints.insert(aConstraint);
+    }
+  }
+  // Fix base features for mirror
+  if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+    AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+        theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_B()));
+    fixFeaturesList(aRefList);
+  }
+
+  if (!myFeatureStorage)
+    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+  myFeatureStorage->changeConstraint(theConstraint);
+
+  return true;
+}
+
+
+bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+  std::set<ConstraintPtr> aConstraints =
+      myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
+  if (aConstraints.empty())
+    return false;
+  std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+  for (; aCIter != aConstraints.end(); aCIter++) {
+    ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
+    aSolConIter->second->update();
+  }
+  return true;
+}
+
+void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+  updateFeature(theFeature);
+  // Temporary rigid constraint
+  SolverConstraintPtr aConstraint =
+      SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature);
+  if (!aConstraint)
+    return;
+  aConstraint->setGroup(this);
+  aConstraint->setStorage(myStorage);
+  myTempConstraints.insert(aConstraint);
+}
+
+// ============================================================================
+//  Function: fixFeaturesList
+//  Class:    SketchSolver_Group
+//  Purpose:  Apply temporary rigid constraints for the list of features
+// ============================================================================
+void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
+{
+  std::list<ObjectPtr> aList = theList->list();
+  std::list<ObjectPtr>::iterator anIt = aList.begin();
+  for (; anIt != aList.end(); anIt++) {
+    if (!(*anIt))
+      continue;
+    FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+    SolverConstraintPtr aConstraint =
+        SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+    if (!aConstraint)
+      continue;
+    aConstraint->setGroup(this);
+    aConstraint->setStorage(myStorage);
+    myTempConstraints.insert(aConstraint);
+  }
+}
+
+// ============================================================================
+//  Function: addWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  create workplane for the group
+// ============================================================================
+bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
+{
+  if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+    return false;  // the workplane already exists or the function parameter is not Sketch
+
+  mySketch = theSketch;
+  updateWorkplane();
+  return true;
+}
+
+// ============================================================================
+//  Function: updateWorkplane
+//  Class:    SketchSolver_Group
+//  Purpose:  update parameters of workplane
+// ============================================================================
+bool SketchSolver_Group::updateWorkplane()
+{
+  if (!myStorage) // Create storage if not exists
+    myStorage = StoragePtr(new SketchSolver_Storage);
+  SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+
+  std::vector<Slvs_Entity> anEntities;
+  std::vector<Slvs_Param> aParams;
+  if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
+    return false;
+
+  if (myWorkplaneID == SLVS_E_UNKNOWN) {
+    myWorkplaneID = anEntities.back().h;
+    // Add new workplane elements
+    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+    for (; aParIter != aParams.end(); aParIter++) {
+      aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+      aParIter->group = myID;
+      aParIter->h = myStorage->addParameter(*aParIter);
+    }
+    std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
+    for (; anEntIter != anEntities.end(); anEntIter++) {
+      anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
+      anEntIter->group = myID;
+      anEntIter->wrkpl = myWorkplaneID;
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->param[i] != SLVS_E_UNKNOWN)
+          anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->point[i] != SLVS_E_UNKNOWN)
+          anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
+      anEntIter->h = myStorage->addEntity(*anEntIter);
+    }
+  } else {
+    // Update existent workplane
+    const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
+    const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
+    const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
+    // Get parameters and update them
+    Slvs_hParam aWPParams[7] = {
+        anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
+        aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
+      };
+    std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
+    for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
+      Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
+      aParam.val = aParIter->val;
+      myStorage->updateParameter(aParam);
+    }
+  }
+  return myWorkplaneID > 0;
+}
+
+// ============================================================================
+//  Function: resolveConstraints
+//  Class:    SketchSolver_Group
+//  Purpose:  solve the set of constraints for the current group
+// ============================================================================
+bool SketchSolver_Group::resolveConstraints()
+{
+  bool aResolved = false;
+  if (myStorage->isNeedToResolve() && !isEmpty()) {
+    myConstrSolver.setGroupID(myID);
+    myStorage->initializeSolver(myConstrSolver);
+
+    int aResult = myConstrSolver.solve();
+    if (aResult == SLVS_RESULT_OKAY) {  // solution succeeded, store results into correspondent attributes
+      myFeatureStorage->blockEvents(true);
+      ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
+      for (; aConstrIter != myConstraints.end(); aConstrIter++)
+        aConstrIter->second->refresh();
+      myFeatureStorage->blockEvents(false);
+    } else if (!myConstraints.empty())
+      Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+
+    aResolved = true;
+  }
+  removeTemporaryConstraints();
+  myStorage->setNeedToResolve(false);
+  return aResolved;
+}
+
+// ============================================================================
+//  Function: mergeGroups
+//  Class:    SketchSolver_Group
+//  Purpose:  append specified group to the current group
+// ============================================================================
+void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
+{
+  // If specified group is empty, no need to merge
+  if (theGroup.isEmpty())
+    return;
+  if (!myFeatureStorage)
+    myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
+
+  ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
+  for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
+    changeConstraint(aConstrIter->first);
+}
+
+// ============================================================================
+//  Function: splitGroup
+//  Class:    SketchSolver_Group
+//  Purpose:  divide the group into several subgroups
+// ============================================================================
+void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+{
+  // Obtain constraints, which should be separated
+  FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
+  std::vector<ConstraintPtr> anUnusedConstraints;
+  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+  for ( ; aCIter != myConstraints.end(); aCIter++) {
+    std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
+    std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
+    for (; anIter != aBaseConstraints.end(); anIter++)
+      if (aNewFeatStorage->isInteract(*anIter)) {
+        aNewFeatStorage->changeConstraint(*anIter);
+      } else
+        anUnusedConstraints.push_back(*anIter);
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aCutsIter;
+  std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+  for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+    // Remove unused constraints
+    removeConstraint(*aUnuseIt);
+    // Try to append constraint to already existent group
+    for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+      if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+        (*aCutsIter)->changeConstraint(*aUnuseIt);
+        break;
+      }
+    if (aCutsIter == theCuts.end()) {
+      // Add new group
+      SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
+      aGroup->changeConstraint(*aUnuseIt);
+      theCuts.push_back(aGroup);
+    }
+  }
+}
+
+// ============================================================================
+//  Function: isConsistent
+//  Class:    SketchSolver_Group
+//  Purpose:  search removed entities and constraints
+// ============================================================================
+bool SketchSolver_Group::isConsistent()
+{
+  if (!myFeatureStorage) // no one constraint is initialized yet
+    return true;
+
+  bool aResult = myFeatureStorage->isConsistent();
+  if (!aResult) {
+    // remove invalid entities
+    ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+    while (aCIter != myConstraints.end()) {
+      std::list<ConstraintPtr> aConstraints = aCIter->second->constraints();
+      std::list<ConstraintPtr>::iterator anIt = aConstraints.begin();
+      for (; anIt != aConstraints.end(); anIt++)
+        if (!(*anIt)->data() || !(*anIt)->data()->isValid())
+          if (aCIter->second->remove(*anIt)) {
+            // the constraint is fully removed, detach it from the list
+            ConstraintConstraintMap::iterator aTmpIt = aCIter++;
+            myFeatureStorage->removeConstraint(aTmpIt->first);
+            myConstraints.erase(aTmpIt);
+            break;
+          }
+      if (anIt == aConstraints.end())
+        aCIter++;
+    }
+  }
+  return aResult;
+}
+
+// ============================================================================
+//  Function: removeTemporaryConstraints
+//  Class:    SketchSolver_Group
+//  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
+//            resolving the set of constraints
+// ============================================================================
+void SketchSolver_Group::removeTemporaryConstraints()
+{
+  myTempConstraints.clear();
+  // Clean lists of removed entities in the storage
+  std::set<Slvs_hParam> aRemPar;
+  std::set<Slvs_hEntity> aRemEnt;
+  std::set<Slvs_hConstraint> aRemCon;
+  myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+  myStorage->setNeedToResolve(false);
+}
+
+// ============================================================================
+//  Function: removeConstraint
+//  Class:    SketchSolver_Group
+//  Purpose:  remove constraint and all unused entities
+// ============================================================================
+void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
+{
+  myFeatureStorage->removeConstraint(theConstraint);
+  ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (aCIter->second->hasConstraint(theConstraint)) {
+      if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+        aCIter = myConstraints.end();
+      break;
+    }
+  if (aCIter != myConstraints.end())
+    myConstraints.erase(aCIter);
+}
diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h
new file mode 100644 (file)
index 0000000..30d675c
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Group.h
+// Created: 27 May 2014
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Group_H_
+#define SketchSolver_Group_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+#include <SketchSolver_Storage.h>
+#include <SketchSolver_FeatureStorage.h>
+#include <SketchSolver_Solver.h>
+
+#include <SketchPlugin_Constraint.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_AttributeRefList.h>
+
+#include <memory>
+#include <list>
+#include <map>
+#include <vector>
+#include <set>
+
+typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
+
+/** \class   SketchSolver_Group
+ *  \ingroup Plugins
+ *  \brief   Keeps the group of constraints which based on the same entities
+ */
+class SketchSolver_Group
+{
+ public:
+  /** \brief New group based on specified workplane.
+   *         Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type
+   *  \remark Type of theSketch is not verified inside
+   */
+  SketchSolver_Group(std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane);
+
+  ~SketchSolver_Group();
+
+  /// \brief Returns group's unique identifier
+  inline const Slvs_hGroup& getId() const
+  {
+    return myID;
+  }
+
+  /// \brief Returns identifier of the workplane
+  inline const Slvs_hEntity& getWorkplaneId() const
+  {
+    return myWorkplaneID;
+  }
+
+  /// \brief Find the identifier of the feature, if it already exists in the group
+  Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
+  /// \brief Find the identifier of the attribute, if it already exists in the group
+  Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
+
+  /// \brief Returns true if the group has no constraints yet
+  inline bool isEmpty() const
+  {
+    return myConstraints.empty();
+  }
+
+  /// \brief Check for valid sketch data
+  inline bool isWorkplaneValid() const
+  {
+    return mySketch->data() && mySketch->data()->isValid();
+  }
+
+  /** \brief Adds or updates a constraint in the group
+   *  \param[in] theConstraint constraint to be changed
+   *  \return \c true if the constraint added or updated successfully
+   */
+  bool changeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Updates the data corresponding the specified feature
+   *  \param[in] theFeature the feature to be updated
+   */
+  bool updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+  /** \brief Updates the data corresponding the specified feature moved in GUI.
+   *         Additional Fixed constraints are created.
+   *  \param[in] theFeature the feature to be updated
+   */
+  void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+  /** \brief Verifies the feature attributes are used in this group
+   *  \param[in] theFeature constraint or any other object for verification of interaction
+   *  \return \c true if some of attributes are used in current group
+   */
+  bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+  /** \brief Verifies the specified feature is equal to the base workplane for this group
+   *  \param[in] theWorkplane the feature to be compared with base workplane
+   *  \return \c true if workplanes are the same
+   */
+  bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const;
+
+  /// Returns the current workplane
+  std::shared_ptr<ModelAPI_CompositeFeature> getWorkplane() const
+  {
+    return mySketch;
+  }
+
+  /** \brief Update parameters of workplane. Should be called when Update event is coming.
+   *  \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
+   */
+  bool updateWorkplane();
+
+  /** \brief Searches invalid features and constraints in the group and removes them
+   *  \return \c false if the group several constraints were removed
+   */
+  bool isConsistent();
+
+  /** \brief Add specified group to this one
+   *  \param[in] theGroup group of constraint to be added
+   */
+  void mergeGroups(const SketchSolver_Group& theGroup);
+
+  /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
+   *  \param[out] theCuts enlarge this list by newly created groups
+   */
+  void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+
+  /** \brief Start solution procedure if necessary and update attributes of features
+   *  \return \c false when no need to solve constraints
+   */
+  bool resolveConstraints();
+
+protected:
+  /** \brief Removes constraints from the group
+   *  \param[in] theConstraint constraint to be removed
+   */
+  void removeConstraint(ConstraintPtr theConstraint);
+
+  /** \brief Remove all temporary constraint after computation finished
+   *  \param[in] theRemoved  indexes of constraints to be removed. If empty, all temporary constraints should be deleted
+   */
+  void removeTemporaryConstraints();
+
+private:
+  /** \brief Creates a workplane from the sketch parameters
+   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
+   *  \return \c true if success, \c false if workplane parameters are not consistent
+   */
+  bool addWorkplane(CompositeFeaturePtr theSketch);
+
+  /// \brief Apply temporary rigid constraints for the list of features
+  void fixFeaturesList(AttributeRefListPtr theList);
+
+private:
+  Slvs_hGroup myID; ///< Index of the group
+  Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+  CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
+  ConstraintConstraintMap myConstraints; ///< List of constraints
+  std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
+
+  StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
+  FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
+
+  SketchSolver_Solver myConstrSolver;  ///< Solver for set of equations obtained by constraints
+};
+
+#endif
index 7e3a33de2891d609d769b2505179b7a2f46f91b4..0e7b1761cc51e62b2aeeede9ce12c1c952d9f51c 100644 (file)
@@ -31,83 +31,46 @@ SketchSolver_Solver::SketchSolver_Solver()
 
 SketchSolver_Solver::~SketchSolver_Solver()
 {
-  if (myEquationsSystem.param)
-    delete[] myEquationsSystem.param;
-  if (myEquationsSystem.entity)
-    delete[] myEquationsSystem.entity;
   if (myEquationsSystem.constraint)
     delete[] myEquationsSystem.constraint;
   if (myEquationsSystem.failed)
     delete[] myEquationsSystem.failed;
 }
 
-void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParameters)
+void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
 {
-  if (theParameters.size() != myEquationsSystem.params)  // number of parameters was changed => reallocate the memory
-      {
-    if (myEquationsSystem.param)
-      delete[] myEquationsSystem.param;
-    myEquationsSystem.params = theParameters.size();
-    myEquationsSystem.param = new Slvs_Param[theParameters.size()];
-  }
-
-  // Copy data
-  std::vector<Slvs_Param>::const_iterator aParamIter = theParameters.begin();
-  for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
-    myEquationsSystem.param[i] = *aParamIter;
+  myEquationsSystem.param = theParameters;
+  myEquationsSystem.params = theSize;
 }
 
-void SketchSolver_Solver::setDraggedParameters(const std::vector<Slvs_hParam>& theDragged)
+
+void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
 {
-  if (theDragged.size() == 0) {
-    myEquationsSystem.dragged[0] = 0;
-    myEquationsSystem.dragged[1] = 0;
-    myEquationsSystem.dragged[2] = 0;
-    myEquationsSystem.dragged[3] = 0;
-    return;
-  }
-  for (unsigned int i = 0; i < theDragged.size(); i++)
+  for (unsigned int i = 0; i < 4; i++)
     myEquationsSystem.dragged[i] = theDragged[i];
 }
 
-void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
+void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
 {
-  if (theEntities.size() != myEquationsSystem.entities)  // number of entities was changed => reallocate the memory
-      {
-    if (myEquationsSystem.entity)
-      delete[] myEquationsSystem.entity;
-    myEquationsSystem.entities = theEntities.size();
-    myEquationsSystem.entity = new Slvs_Entity[theEntities.size()];
-  }
-
-  // Copy data
-  std::vector<Slvs_Entity>::const_iterator aEntIter = theEntities.begin();
-  for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++)
-    myEquationsSystem.entity[i] = *aEntIter;
+  myEquationsSystem.entity = theEntities;
+  myEquationsSystem.entities = theSize;
 }
 
-void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& theConstraints)
+void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
 {
-  if (theConstraints.size() != myEquationsSystem.constraints)  // number of constraints was changed => reallocate the memory
-      {
-    if (myEquationsSystem.constraint)
-      delete[] myEquationsSystem.constraint;
-    myEquationsSystem.constraints = theConstraints.size();
-    myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
-
-    // Assign the memory for the failed constraints
-    if (myEquationsSystem.failed)
-      delete[] myEquationsSystem.failed;
-    myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()];
-    myEquationsSystem.faileds = theConstraints.size();
+  if (!myEquationsSystem.constraint) {
+    myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+    myEquationsSystem.constraints = theSize;
   }
-
-  // Copy data
-  std::vector<Slvs_Constraint>::const_iterator aConstrIter = theConstraints.begin();
-  for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++)
-    myEquationsSystem.constraint[i] = *aConstrIter;
+  else if (myEquationsSystem.constraints != theSize) {
+    delete[] myEquationsSystem.constraint;
+    myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+    myEquationsSystem.constraints = theSize;
+  }
+  memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
 }
 
+
 int SketchSolver_Solver::solve()
 {
   if (myEquationsSystem.constraints <= 0)
index 4a45b525343b64936823d677135795b90b243009..bdc23ce288182adff99c5752d3f0befc5d06e60f 100644 (file)
@@ -28,6 +28,8 @@ typedef unsigned int UINT32;
 #define SLVS_C_FILLET 100100
 // Unknown entity
 #define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
 
 /**
  * The main class that performs the high-level operations for connection to the SolveSpace.
@@ -46,25 +48,28 @@ class SketchSolver_Solver
   }
 
   /** \brief Change array of parameters
-   *  \param[in] theParameters vector of parameters
+   *  \param[in] theParameters pointer to the array of parameters
+   *  \param[in] theSize       size of this array
    */
-  void setParameters(const std::vector<Slvs_Param>& theParameters);
+  void setParameters(Slvs_Param* theParameters, int theSize);
 
   /** \brief Change array of entities
-   *  \param[in] theEntities vector of entities
+   *  \param[in] theEntities pointer to the array of entities
+   *  \param[in] theSize     size of this array
    */
-  void setEntities(const std::vector<Slvs_Entity>& theEntities);
+  void setEntities(Slvs_Entity* theEntities, int theSize);
 
   /** \brief Change array of constraints
-   *  \param[in] theConstraints vector of constraints
+   *  \param[in] theConstraints pointer to the array of constraints
+   *  \param[in] theSize        size of this array
    */
-  void setConstraints(const std::vector<Slvs_Constraint>& theConstraints);
+  void setConstraints(Slvs_Constraint* theConstraints, int theSize);
 
   /** \brief Store the parameters of the point which was moved by user.
    *         The solver will watch this items to be constant
    *  \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
    */
-  void setDraggedParameters(const std::vector<Slvs_hParam>& theDragged);
+  void setDraggedParameters(const Slvs_hParam* theDragged);
 
   /** \brief Solve the set of equations
    *  \return identifier whether solution succeeded
diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp
new file mode 100644 (file)
index 0000000..d4a5171
--- /dev/null
@@ -0,0 +1,471 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include <SketchSolver_Storage.h>
+
+#include <math.h>
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ *  \param[in] theEntityID unique ID of the element
+ *  \param[in] theEntities list of elements
+ *  \return position of the found element or -1 if the element is not found
+ */
+template<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+/// \brief Compare two parameters to be different
+static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2);
+/// \brief Compare two entities to be different
+static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2);
+/// \brief Compare two constriants to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SketchSolver_Storage::SketchSolver_Storage()
+  : myParamMaxID(SLVS_E_UNKNOWN),
+    myEntityMaxID(SLVS_E_UNKNOWN),
+    myConstrMaxID(SLVS_C_UNKNOWN),
+    myFixed(SLVS_E_UNKNOWN),
+    myNeedToResolve(false)
+{
+}
+
+Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter is already used, rewrite it
+    return updateParameter(theParam);
+  }
+
+  Slvs_Param aParam = theParam;
+  if (aParam.h > myParamMaxID)
+    myParamMaxID = aParam.h;
+  else
+    aParam.h = ++myParamMaxID;
+  myParameters.push_back(aParam);
+  myNeedToResolve = true;
+  return aParam.h;
+}
+
+Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+  if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+    // parameter already used, rewrite it
+    int aPos = Search(theParam.h, myParameters);
+    if (aPos >= 0 && aPos < (int)myParameters.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam);
+      myParameters[aPos] = theParam;
+      return theParam.h;
+    }
+  }
+
+  // Parameter is not found, add new one
+  Slvs_Param aParam = theParam;
+  aParam.h = 0;
+  return addParameter(aParam);
+}
+
+bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size()) {
+    // Firstly, search the parametes is not used elsewhere
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->param[i] == theParamID)
+          return false;
+    }
+    // Remove parameter
+    myParameters.erase(myParameters.begin() + aPos);
+    myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
+    myNeedToResolve = true;
+    myRemovedParameters.insert(theParamID);
+    return true;
+  }
+  return false;
+}
+
+const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+  int aPos = Search(theParamID, myParameters);
+  if (aPos >= 0 && aPos < (int)myParameters.size())
+    return myParameters[aPos];
+
+  // Parameter is not found, return empty object
+  static Slvs_Param aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+
+Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity is already used, rewrite it
+    return updateEntity(theEntity);
+  }
+
+  Slvs_Entity aEntity = theEntity;
+  if (aEntity.h > myEntityMaxID)
+    myEntityMaxID = aEntity.h;
+  else
+    aEntity.h = ++myEntityMaxID;
+  myEntities.push_back(aEntity);
+  myNeedToResolve = true;
+  return aEntity.h;
+}
+
+Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+  if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+    // Entity already used, rewrite it
+    int aPos = Search(theEntity.h, myEntities);
+    if (aPos >= 0 && aPos < (int)myEntities.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+      myEntities[aPos] = theEntity;
+      return theEntity.h;
+    }
+  }
+
+  // Entity is not found, add new one
+  Slvs_Entity aEntity = theEntity;
+  aEntity.h = 0;
+  return addEntity(aEntity);
+}
+
+bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+  bool aResult = true;
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size()) {
+    // Firstly, check the entity is not used elsewhere
+    std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+    for (; anEntIter != myEntities.end(); anEntIter++) {
+      for (int i = 0; i < 4; i++)
+        if (anEntIter->point[i] == theEntityID)
+          return false;
+      if (anEntIter->distance == theEntityID)
+        return false;
+    }
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+      Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+          aConstrIter->entityA, aConstrIter->entityB,
+          aConstrIter->entityC, aConstrIter->entityD};
+      for (int i = 0; i < 6; i++)
+        if (anEntIDs[i] == theEntityID)
+          return false;
+    }
+    // The entity is not used, remove it and its parameters
+    Slvs_Entity anEntity = myEntities[aPos];
+    myEntities.erase(myEntities.begin() + aPos);
+    myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+    if (anEntity.distance != SLVS_E_UNKNOWN)
+      aResult = aResult && removeParameter(anEntity.distance);
+    for (int i = 0; i < 4; i++)
+      if (anEntity.param[i] != SLVS_E_UNKNOWN)
+        aResult = removeParameter(anEntity.param[i]) && aResult;
+    for (int i = 0; i < 4; i++)
+      if (anEntity.point[i] != SLVS_E_UNKNOWN)
+        aResult = removeEntity(anEntity.point[i]) && aResult;
+    myNeedToResolve = true;
+    myRemovedEntities.insert(theEntityID);
+    if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
+      removeCoincidentPoint(theEntityID);
+  }
+  return aResult;
+}
+
+const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+  int aPos = Search(theEntityID, myEntities);
+  if (aPos >= 0 && aPos < (int)myEntities.size())
+    return myEntities[aPos];
+
+  // Entity is not found, return empty object
+  static Slvs_Entity aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const
+{
+  // Search the set of coincident points
+  std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
+  for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
+    if (aCPIter->find(thePointID) != aCPIter->end())
+      break;
+  if (aCPIter == myCoincidentPoints.end()) {
+    std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+    for (; aConstrIter != myConstraints.end(); aConstrIter++)
+      if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+          aConstrIter->ptA == thePointID)
+        return aConstrIter->h;
+    return SLVS_E_UNKNOWN;
+  }
+
+  // Search the Rigid constraint
+  std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+  for (; aConstrIter != myConstraints.end(); aConstrIter++)
+    if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+        aCPIter->find(aConstrIter->ptA) != aCPIter->end())
+      return aConstrIter->h;
+  return SLVS_E_UNKNOWN;
+}
+
+
+Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint is already used, rewrite it
+    return updateConstraint(theConstraint);
+  }
+
+  Slvs_Constraint aConstraint = theConstraint;
+
+  // Find a constraint with same type uses same arguments
+  std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+  for (; aCIt != myConstraints.end(); aCIt++) {
+    if (aConstraint.type != aCIt->type)
+      continue;
+    if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+        aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+        aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) {
+      aConstraint.h = aCIt->h;
+      return updateConstraint(aConstraint);
+    }
+  }
+
+  if (aConstraint.h > myConstrMaxID)
+    myConstrMaxID = aConstraint.h;
+  else
+    aConstraint.h = ++myConstrMaxID;
+  myConstraints.push_back(aConstraint);
+  myNeedToResolve = true;
+  if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
+    addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
+  return aConstraint.h;
+}
+
+Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+  if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+    // Constraint already used, rewrite it
+    int aPos = Search(theConstraint.h, myConstraints);
+    if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+      myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+      myConstraints[aPos] = theConstraint;
+      if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
+        addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
+      return theConstraint.h;
+    }
+  }
+
+  // Constraint is not found, add new one
+  Slvs_Constraint aConstraint = theConstraint;
+  aConstraint.h = 0;
+  return addConstraint(aConstraint);
+}
+
+bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  bool aResult = true;
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+    Slvs_Constraint aConstraint = myConstraints[aPos];
+    myConstraints.erase(myConstraints.begin() + aPos);
+    myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
+    myNeedToResolve = true;
+    myRemovedConstraints.insert(theConstraintID);
+    // Remove all entities
+    Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+        aConstraint.entityA, aConstraint.entityB,
+        aConstraint.entityC, aConstraint.entityD};
+    for (int i = 0; i < 6; i++)
+      if (anEntities[i] != SLVS_E_UNKNOWN)
+        aResult = removeEntity(anEntities[i]) && aResult;
+    // remove temporary fixed point, if available
+    if (myFixed == theConstraintID)
+      myFixed = SLVS_E_UNKNOWN;
+  }
+  return aResult;
+}
+
+const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size())
+    return myConstraints[aPos];
+
+  // Constraint is not found, return empty object
+  static Slvs_Constraint aDummy;
+  aDummy.h = 0;
+  return aDummy;
+}
+
+std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
+{
+  std::list<Slvs_Constraint> aResult;
+  std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+  for (; aCIter != myConstraints.end(); aCIter++)
+    if (aCIter->type == theConstraintType)
+      aResult.push_back(*aCIter);
+  return aResult;
+}
+
+
+void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+  if (myFixed != SLVS_E_UNKNOWN)
+    return; // the point is already fixed
+  int aPos = Search(theConstraintID, myConstraints);
+  if (aPos >= 0 && aPos < (int)myConstraints.size())
+    myFixed = theConstraintID;
+}
+
+void SketchSolver_Storage::getRemoved(
+    std::set<Slvs_hParam>& theParameters,
+    std::set<Slvs_hEntity>& theEntities,
+    std::set<Slvs_hConstraint>& theConstraints)
+{
+  theParameters = myRemovedParameters;
+  theEntities = myRemovedEntities;
+  theConstraints = myRemovedConstraints;
+
+  myRemovedParameters.clear();
+  myRemovedEntities.clear();
+  myRemovedConstraints.clear();
+}
+
+void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+{
+  theSolver.setParameters(myParameters.data(), (int)myParameters.size());
+  theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+
+  // Copy constraints excluding the fixed one
+  std::vector<Slvs_Constraint> aConstraints = myConstraints;
+  if (myFixed != SLVS_E_UNKNOWN) {
+    Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
+    std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
+    for (; anIt != aConstraints.end(); anIt++)
+      if (anIt->h == myFixed) {
+        aFixedPoint = anIt->ptA;
+        aConstraints.erase(anIt);
+        break;
+      }
+    // set dragged parameters
+    int aPos = Search(aFixedPoint, myEntities);
+    theSolver.setDraggedParameters(myEntities[aPos].param);
+  }
+  theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
+}
+
+void SketchSolver_Storage::addCoincidentPoints(
+    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
+{
+  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
+  std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
+  bool isFound = false;
+  for (; aCIter != myCoincidentPoints.end(); aCIter++) {
+    bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
+    bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
+    isFound = isFound || isFirstFound || isSecondFound;
+    if (isFirstFound && isSecondFound)
+      break; // already coincident
+    else if (isFirstFound || isSecondFound) {
+      if (aFoundIter != myCoincidentPoints.end()) {
+        // merge two sets
+        aFoundIter->insert(aCIter->begin(), aCIter->end());
+        myCoincidentPoints.erase(aCIter);
+        break;
+      }
+      aCIter->insert(thePoint1);
+      aCIter->insert(thePoint2);
+    }
+  }
+  // coincident points not found
+  if (!isFound) {
+    std::set<Slvs_hEntity> aNewSet;
+    aNewSet.insert(thePoint1);
+    aNewSet.insert(thePoint2);
+    myCoincidentPoints.push_back(aNewSet);
+  }
+}
+
+void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
+{
+  std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
+  for (; aCIter != myCoincidentPoints.end(); aCIter++)
+    if (aCIter->find(thePoint) != aCIter->end()) {
+      aCIter->erase(thePoint);
+      if (aCIter->size() <= 1)
+        myCoincidentPoints.erase(aCIter);
+      break;
+    }
+}
+
+bool SketchSolver_Storage::isCoincident(
+    const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
+{
+  std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
+  for (; aCIter != myCoincidentPoints.end(); aCIter++)
+    if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
+      return true;
+  return false;
+}
+
+
+
+
+// ========================================================
+// =========      Auxiliary functions       ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+  int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+  int aVecSize = theEntities.size();
+  if (theEntities.empty())
+    return 1;
+  while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+    aResIndex--;
+  while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+    aResIndex++;
+  if (aResIndex == -1)
+    aResIndex = aVecSize;
+  return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+  return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+  int i = 0;
+  for (; theEntity1.param[i] != 0 && i < 4; i++)
+    if (theEntity1.param[i] != theEntity2.param[i])
+      return true;
+  i = 0;
+  for (; theEntity1.point[i] != 0 && i < 4; i++)
+    if (theEntity1.point[i] != theEntity2.point[i])
+      return true;
+  return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+  return theConstraint1.ptA != theConstraint2.ptA ||
+         theConstraint1.ptB != theConstraint2.ptB ||
+         theConstraint1.entityA != theConstraint2.entityA ||
+         theConstraint1.entityB != theConstraint2.entityB ||
+         theConstraint1.entityC != theConstraint2.entityC ||
+         theConstraint1.entityD != theConstraint2.entityD ||
+         fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h
new file mode 100644 (file)
index 0000000..cf04f47
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:    SketchSolver_Storage.h
+// Created: 18 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchSolver_Storage_H_
+#define SketchSolver_Storage_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Solver.h>
+
+#include <list>
+#include <memory>
+#include <set>
+#include <vector>
+
+/** \class   SketchSolver_Storage
+ *  \ingroup Plugins
+ *  \brief   Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SketchSolver_Storage
+{
+public:
+  SketchSolver_Storage();
+
+  /** \brief Add new parameter to the current group
+   *  \param[in] theParam  SolveSpace parameter
+   *  \return the ID of added parameter
+   */
+  Slvs_hParam addParameter(const Slvs_Param& theParam);
+  /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added
+   *  \param[in] theParam  SolveSpace parameter
+   *  \return the ID of updated/added parameter
+   */
+  Slvs_hParam updateParameter(const Slvs_Param& theParam);
+  /** \brief Removes the parameter by its ID
+   *  \param[in] theParamID  index of parameter to be removed
+   *  \return \c true if the parameter was successfully removed
+   */
+  bool removeParameter(const Slvs_hParam& theParamID);
+  /// \brief Returns the parameter by its ID
+  const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const;
+
+  /** \brief Add new entity to the current group
+   *  \param[in] theEntity  SolveSpace entity
+   *  \return the ID of added entity
+   */
+  Slvs_hEntity addEntity(const Slvs_Entity& theEntity);
+  /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added
+   *  \param[in] theEntity  SolveSpace entity
+   *  \return the ID of updated/added entity
+   */
+  Slvs_hEntity updateEntity(const Slvs_Entity& theEntity);
+  /** \brief Removes the entity by its ID. All parameters used in this entity,
+   *         and not used in other constraints, will be removed too.
+   *  \param[in] theEntityID  index of entity to be removed
+   *  \return \c true if the entity was successfully removed
+   */
+  bool removeEntity(const Slvs_hEntity& theEntityID);
+  /// \brief Returns the entity by its ID
+  const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const;
+
+  /// \brief Verifies the current point or another coincident one is fixed
+  /// \return the ID of the Fixed constraint or SLVS_E_UNKNOWN
+  Slvs_hConstraint isPointFixed(const Slvs_hEntity& thePointID) const;
+
+  /** \brief Add new constraint to the current group
+   *  \param[in] theConstraint   SolveSpace's constraint
+   *  \return the ID of added constraint
+   */
+  Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint);
+  /** \brief Updates constraint in the current group.
+   *         If the ID of constraint is zero, the new item will be added
+   *  \param[in] theConstraint  SolveSpace constraint
+   *  \return the ID of updated/added constraint
+   */
+  Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint);
+  /** \brief Removes the constraint by its ID. All entities and parameters depending on this
+   *         constraint, which are not used in other constraints, will be removed too.
+   *  \param[in] theConstraintID  index of constraint to be removed
+   *  \return \c true if the constraint was successfully removed
+   */
+  bool removeConstraint(const Slvs_hConstraint& theConstraintID);
+  /// \brief Returns the constraint by its ID
+  const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const;
+  /// \brief Returns list of constraints of specified type
+  std::list<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
+
+  /// \brief Attach temporary constraint to this storage. It need to make precise calculations
+  void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID);
+
+  /// \brief Shows the sketch should be resolved
+  bool isNeedToResolve() const
+  { return myNeedToResolve; }
+
+  /// \brief Changes the flag of group to be resolved
+  void setNeedToResolve(bool theFlag)
+  { myNeedToResolve = theFlag; }
+
+  /// \brief Returns lists of removed elements
+  void getRemoved(std::set<Slvs_hParam>& theParameters,
+                  std::set<Slvs_hEntity>& theEntities,
+                  std::set<Slvs_hConstraint>& theConstraints);
+
+  /// \brief Initialize constraint solver by the entities collected by current storage
+  void initializeSolver(SketchSolver_Solver& theSolver);
+
+private:
+  /// \brief Store coincident points
+  void addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2);
+  /// \brief Remove point from lists of coincidence
+  void removeCoincidentPoint(const Slvs_hEntity& thePoint);
+
+public:
+  /// \brief Check two points are coincident
+  bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const;
+
+private:
+  Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
+  std::vector<Slvs_Param> myParameters; ///< list of parameters used in the current group of constraints (sorted by the identifier)
+  Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities)
+  std::vector<Slvs_Entity> myEntities; ///< list of entities used in the current group of constraints (sorted by the identifier)
+  Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints)
+  std::vector<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group (sorted by the identifier)
+
+  std::vector< std::set<Slvs_hEntity> > myCoincidentPoints; ///< lists of coincident points
+  Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+
+  bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
+
+  std::set<Slvs_hParam> myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant)
+  std::set<Slvs_hEntity> myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant)
+  std::set<Slvs_hConstraint> myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant)
+};
+
+typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
+
+#endif
index 86f1a1f3e53fee0ca76d99dfa9c9b1ab4ed8b056..3520df99884db5881a6d22137b95cf51e6b08dca 100644 (file)
@@ -16,8 +16,6 @@
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_Pnt2d.h>
 
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Constraint.h>
 
 #include <AIS_Drawer.hxx>
@@ -33,7 +31,7 @@
 IMPLEMENT_STANDARD_HANDLE(SketcherPrs_Coincident, AIS_InteractiveObject);
 IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Coincident, AIS_InteractiveObject);
 
-SketcherPrs_Coincident::SketcherPrs_Coincident(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Coincident::SketcherPrs_Coincident(ModelAPI_Feature* theConstraint, 
                                                const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : AIS_InteractiveObject(), myConstraint(theConstraint), myPlane(thePlane)
 {
@@ -72,9 +70,11 @@ void SketcherPrs_Coincident::Compute(const Handle(PrsMgr_PresentationManager3d)&
 void SketcherPrs_Coincident::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
                                             const Standard_Integer aMode)
 {
-  Handle(SelectMgr_EntityOwner) aOwn = new SelectMgr_EntityOwner(this, 10);
-  Handle(Select3D_SensitivePoint) aSp = new Select3D_SensitivePoint(aOwn, myPoint);
-  aSelection->Add(aSp);
+  if ((aMode == 0) || (aMode == SketcherPrs_Tools::Sel_Constraint)) {
+    Handle(SelectMgr_EntityOwner) aOwn = new SelectMgr_EntityOwner(this, 10);
+    Handle(Select3D_SensitivePoint) aSp = new Select3D_SensitivePoint(aOwn, myPoint);
+    aSelection->Add(aSp);
+  }
 }
 
 void SketcherPrs_Coincident::SetColor(const Quantity_NameOfColor aCol)
index 72c7ec5d01a9494ab707016fc3bc8fae66e0b9d0..5aaf5d63589530db34843fe57517504a01cd1020 100644 (file)
@@ -8,12 +8,11 @@
 #define SketcherPrs_Coincident_H
 
 #include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
 
 #include <AIS_InteractiveObject.hxx>
 #include <Standard_DefineHandle.hxx>
 
-class SketchPlugin_Constraint;
-
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_Coincident, AIS_InteractiveObject)
 
@@ -27,7 +26,7 @@ class SketcherPrs_Coincident: public AIS_InteractiveObject
 public:
   /// Constructor
   /// \param theResult a result object
-  Standard_EXPORT SketcherPrs_Coincident(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Coincident(ModelAPI_Feature* theConstraint, 
                                          const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   Standard_EXPORT virtual void SetColor(const Quantity_Color& aColor);
@@ -45,7 +44,7 @@ protected:
     const Standard_Integer aMode) ;
 
 private:
-  SketchPlugin_Constraint* myConstraint;
+  ModelAPI_Feature* myConstraint;
   std::shared_ptr<GeomAPI_Ax3> myPlane;
   gp_Pnt myPoint;
 };
index 7ba9a3f65ab9dddab53078881a589da978d0923a..f26682c3cae4603bccf4c216fc3f7c54691fc9a7 100644 (file)
@@ -19,7 +19,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Equal, SketcherPrs_SymbolPrs);
 
 static Handle(Image_AlienPixMap) MyPixMap;
 
-SketcherPrs_Equal::SketcherPrs_Equal(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Equal::SketcherPrs_Equal(ModelAPI_Feature* theConstraint, 
                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane)
 {
index 4bd1a86ab53a3ec4937a923d145a7383056dd4a3..d958d412488c0c90cbe021e2e81eed08bcd5a35f 100644 (file)
@@ -9,9 +9,6 @@
 
 #include "SketcherPrs_SymbolPrs.h"
 
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
-
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_Equal, SketcherPrs_SymbolPrs)
 
@@ -26,7 +23,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Equal(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Equal(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTI(SketcherPrs_Equal)
 protected:
index 04f9bf3b7fb3e91245bf03097d39f8f6f8ff10bb..7ef2368621dbf5a651055fc64e24a71af6b2fb83 100644 (file)
@@ -17,7 +17,7 @@
 #include "SketcherPrs_LengthDimension.h"
 
 #define CONSTRAINT_PRS_IMPL(NAME, CLASS) \
-AISObjectPtr SketcherPrs_Factory::NAME(SketchPlugin_Constraint* theConstraint, \
+AISObjectPtr SketcherPrs_Factory::NAME(ModelAPI_Feature* theConstraint, \
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane) \
 { \
   std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject()); \
@@ -36,7 +36,7 @@ CONSTRAINT_PRS_IMPL(radiusConstraint, SketcherPrs_Radius);
 CONSTRAINT_PRS_IMPL(lengthDimensionConstraint, SketcherPrs_LengthDimension);
 
 
-AISObjectPtr SketcherPrs_Factory::horisontalConstraint(SketchPlugin_Constraint* theConstraint,
+AISObjectPtr SketcherPrs_Factory::horisontalConstraint(ModelAPI_Feature* theConstraint,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane)
 { 
   std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject()); 
@@ -45,7 +45,7 @@ AISObjectPtr SketcherPrs_Factory::horisontalConstraint(SketchPlugin_Constraint*
   return aAISObj; 
 }
 
-AISObjectPtr SketcherPrs_Factory::verticalConstraint(SketchPlugin_Constraint* theConstraint,
+AISObjectPtr SketcherPrs_Factory::verticalConstraint(ModelAPI_Feature* theConstraint,
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane)
 { 
   std::shared_ptr<GeomAPI_AISObject> aAISObj = AISObjectPtr(new GeomAPI_AISObject()); 
index d416644f9cb315c56555cb9a04aa91bcb70b6d52..c43fb948fed15389e49ed56601f858331dbdb61b 100644 (file)
@@ -9,13 +9,13 @@
 
 #include "SketcherPrs.h"
 
+#include <ModelAPI_Feature.h>
+
 #include <GeomAPI_Ax3.h>
 #include <GeomAPI_AISObject.h>
 
-class SketchPlugin_Constraint;
-
 #define GET_CONSTRAINT_PRS(NAME) \
-  static AISObjectPtr NAME(SketchPlugin_Constraint* theConstraint, \
+  static AISObjectPtr NAME(ModelAPI_Feature* theConstraint, \
                            const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
 
index 5992db2fd4ed128240514a711feb824ea15ec785..b1459205ea1e311efa11dfb672cd284e4a41125c 100644 (file)
@@ -20,7 +20,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_HVDirection, SketcherPrs_SymbolPrs);
 
 static Handle(Image_AlienPixMap) MyPixMap;
 
-SketcherPrs_HVDirection::SketcherPrs_HVDirection(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_HVDirection::SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint, 
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                            bool isHorisontal) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane), myIsHorisontal(isHorisontal)
index 96432d23071a59be989deb477bde3205a5333bed..079991dd285d3b39b9a083aa0cc5c40f518fe954 100644 (file)
@@ -8,9 +8,7 @@
 #define SketcherPrs_HVDirection_H
 
 #include "SketcherPrs_SymbolPrs.h"
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
 
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_HVDirection, SketcherPrs_SymbolPrs)
@@ -26,7 +24,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_HVDirection(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_HVDirection(ModelAPI_Feature* theConstraint, 
                                          const std::shared_ptr<GeomAPI_Ax3>& thePlane,
                                          bool isHorisontal);
 
index 65b067782dcf50b1a9e48efc7241a5c66b3b5ea8..17c316afc3a414b606b02a66dc792276ac62f74b 100644 (file)
@@ -30,7 +30,7 @@ static const gp_Pln MyDefPln(gp_Pnt(0,0,0), gp_Dir(0,0,1));
 IMPLEMENT_STANDARD_HANDLE(SketcherPrs_LengthDimension, AIS_LengthDimension);
 IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_LengthDimension, AIS_LengthDimension);
 
-SketcherPrs_LengthDimension::SketcherPrs_LengthDimension(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_LengthDimension::SketcherPrs_LengthDimension(ModelAPI_Feature* theConstraint, 
                         const std::shared_ptr<GeomAPI_Ax3>& thePlane)
 : AIS_LengthDimension(MyDefStart, MyDefEnd, MyDefPln), 
 myConstraint(theConstraint), myPlane(thePlane)
@@ -126,14 +126,14 @@ bool SketcherPrs_LengthDimension::getPoints(gp_Pnt& thePnt1, gp_Pnt& thePnt2) co
       aPnt_A = aPoint_A->pnt();
       aPnt_B = aPoint_B->pnt();
     } else if (!aPoint_A && aPoint_B) {
-      std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+      FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(
           aData, SketchPlugin_Constraint::ENTITY_A());
       if (aLine) {
         aPnt_B = aPoint_B->pnt();
         aPnt_A = SketcherPrs_Tools::getProjectionPoint(aLine, aPnt_B);
       }
     } else if (aPoint_A && !aPoint_B) {
-      std::shared_ptr<SketchPlugin_Line> aLine = SketcherPrs_Tools::getFeatureLine(
+      FeaturePtr aLine = SketcherPrs_Tools::getFeatureLine(
           aData, SketchPlugin_Constraint::ENTITY_B());
       if (aLine) {
         aPnt_A = aPoint_A->pnt();
@@ -151,3 +151,25 @@ bool SketcherPrs_LengthDimension::getPoints(gp_Pnt& thePnt1, gp_Pnt& thePnt2) co
   }
   return false;
 }
+
+
+
+void SketcherPrs_LengthDimension::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+                                                   const Standard_Integer theMode)
+{
+  Standard_Integer aMode;
+  switch (theMode) {
+  case SketcherPrs_Tools::Sel_Dimension_All:
+    aMode = 0;
+    break;
+  case SketcherPrs_Tools::Sel_Dimension_Line:
+    aMode = 1;
+    break;
+  case SketcherPrs_Tools::Sel_Dimension_Text:
+    aMode = 2;
+    break;
+  default:
+    aMode = theMode;
+  }
+  AIS_LengthDimension::ComputeSelection(aSelection, aMode);
+}
index 94bd89c467c05be720ab8ed4fe64acbae6140afd..5fde8d7aa0e094f1599a18f752c4d9c1b1138e81 100644 (file)
@@ -9,12 +9,11 @@
 #define SketcherPrs_LinearDimension_H
 
 #include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
 #include <AIS_LengthDimension.hxx>
 #include <Standard_DefineHandle.hxx>
 
 
-class SketchPlugin_Constraint;
-
 DEFINE_STANDARD_HANDLE(SketcherPrs_LengthDimension, AIS_LengthDimension)
 
 /**
@@ -28,7 +27,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_LengthDimension(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_LengthDimension(ModelAPI_Feature* theConstraint, 
                         const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   std::string constraintType() const;
@@ -39,11 +38,15 @@ protected:
   Standard_EXPORT virtual void Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
     const Handle(Prs3d_Presentation)& thePresentation, const Standard_Integer theMode = 0);
 
+  /// Redefinition of virtual function
+  Standard_EXPORT virtual void ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+    const Standard_Integer aMode);
+
 private:
   bool getPoints(gp_Pnt& thePnt1, gp_Pnt& thePnt2) const;
 
   /// Constraint feature
-  SketchPlugin_Constraint* myConstraint;
+  ModelAPI_Feature* myConstraint;
 
   /// Plane of the current sketcher
   std::shared_ptr<GeomAPI_Ax3> myPlane;
index 71f97ceda2329387a90395a3e714b81038f2c1e4..e80fb8f784c387190422a6b109c45866e13302b5 100644 (file)
@@ -20,7 +20,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Parallel, SketcherPrs_SymbolPrs);
 
 static Handle(Image_AlienPixMap) MyPixMap;
 
-SketcherPrs_Parallel::SketcherPrs_Parallel(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Parallel::SketcherPrs_Parallel(ModelAPI_Feature* theConstraint, 
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane)
 {
index d0126d30b0e0e8197cff4c5f669c04ad76901493..3194a63cce7c2bc376d37dd38a87944582c8d912 100644 (file)
@@ -9,9 +9,6 @@
 
 #include "SketcherPrs_SymbolPrs.h"
 
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
-
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_Parallel, SketcherPrs_SymbolPrs)
 
@@ -26,7 +23,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Parallel(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Parallel(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   DEFINE_STANDARD_RTTI(SketcherPrs_Parallel)
 protected:
index e00b23d7df1b38283f920035608c9b48ed0c8d54..ecfd72d1181c21d3da822e6086c97f0c46b9497e 100644 (file)
@@ -20,7 +20,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs);
 
 static Handle(Image_AlienPixMap) MyPixMap;
 
-SketcherPrs_Perpendicular::SketcherPrs_Perpendicular(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Perpendicular::SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint, 
                                                      const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane)
 {
index c77a09203bcdb3f0a80ab550f3227845cc301ec4..6cabbf03a4807a5ed0100904bdb30d0c424f8bb6 100644 (file)
@@ -25,7 +25,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Perpendicular(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Perpendicular(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   DEFINE_STANDARD_RTTI(SketcherPrs_Perpendicular)
index 5e30f527fa95dd82ef66758e8b5b27c2e3aedfe6..a3643fe08698926dd83629401a1afe6adeeb77b6 100644 (file)
@@ -23,7 +23,7 @@ static const gp_Circ MyDefCirc(gp_Ax2(gp_Pnt(0,0,0), gp_Dir(0,0,1)), 1);
 IMPLEMENT_STANDARD_HANDLE(SketcherPrs_Radius, AIS_RadiusDimension);
 IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Radius, AIS_RadiusDimension);
 
-SketcherPrs_Radius::SketcherPrs_Radius(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Radius::SketcherPrs_Radius(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane)
 : AIS_RadiusDimension(MyDefCirc), myConstraint(theConstraint), myPlane(thePlane)
 {
@@ -99,3 +99,23 @@ void SketcherPrs_Radius::Compute(const Handle(PrsMgr_PresentationManager3d)& the
 
   AIS_RadiusDimension::Compute(thePresentationManager, thePresentation, theMode);
 }
+
+void SketcherPrs_Radius::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+                                                   const Standard_Integer theMode)
+{
+  Standard_Integer aMode;
+  switch (theMode) {
+  case SketcherPrs_Tools::Sel_Dimension_All:
+    aMode = 0;
+    break;
+  case SketcherPrs_Tools::Sel_Dimension_Line:
+    aMode = 1;
+    break;
+  case SketcherPrs_Tools::Sel_Dimension_Text:
+    aMode = 2;
+    break;
+  default:
+    aMode = theMode;
+  }
+  AIS_RadiusDimension::ComputeSelection(aSelection, aMode);
+}
index 0b32639b761dd209c4b7761ee917b0fe3036fa1d..88a3c613c219d445c55f95b06e018bd38682e8b2 100644 (file)
@@ -9,12 +9,11 @@
 #define SketcherPrs_Radius_H
 
 #include <GeomAPI_Ax3.h>
+#include <ModelAPI_Feature.h>
 
 #include <AIS_RadiusDimension.hxx>
 #include <Standard_DefineHandle.hxx>
 
-class SketchPlugin_Constraint;
-
 DEFINE_STANDARD_HANDLE(SketcherPrs_Radius, AIS_RadiusDimension)
 
 /**
@@ -27,7 +26,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Radius(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Radius(ModelAPI_Feature* theConstraint, 
                         const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   DEFINE_STANDARD_RTTI(SketcherPrs_Radius)
@@ -36,9 +35,13 @@ protected:
   Standard_EXPORT virtual void Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
     const Handle(Prs3d_Presentation)& thePresentation, const Standard_Integer theMode = 0);
 
+  /// Redefinition of virtual function
+  Standard_EXPORT virtual void ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
+    const Standard_Integer aMode);
+
 private:
   /// Constraint feature
-  SketchPlugin_Constraint* myConstraint;
+  ModelAPI_Feature* myConstraint;
 
   /// Plane of the current sketcher
   std::shared_ptr<GeomAPI_Ax3> myPlane;
index 84a36d3c017943d0afa10f58739fc211261ecc17..2a7245e1dfc809d1f91407c2a691f97d4153d632 100644 (file)
@@ -36,7 +36,7 @@ static Handle(Image_AlienPixMap) MyPixMap;
 
 
 
-SketcherPrs_Rigid::SketcherPrs_Rigid(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Rigid::SketcherPrs_Rigid(ModelAPI_Feature* theConstraint, 
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane)
 {
index 5328210773228b7eb49ae2d97703f7bc83f675fb..cabccbf07e2928bae5292a74036ddb4d750409b2 100644 (file)
@@ -9,9 +9,7 @@
 
 #include "SketcherPrs_SymbolPrs.h"
 #include <ModelAPI_Object.h>
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
 
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_Rigid, SketcherPrs_SymbolPrs)
@@ -27,7 +25,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Rigid(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Rigid(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
 
index a74dfc82a763c68c10bebd190dc6902159b3c09d..20fc780a705d564a603b0e8dde375b97e2975123 100644 (file)
@@ -14,6 +14,7 @@
 #include <Graphic3d_BndBox4f.hxx>
 
 #include <SelectMgr_Selection.hxx>
+#include <SelectMgr_SelectionManager.hxx>
 #include <Select3D_SensitivePoint.hxx>
 #include <TopLoc_Location.hxx>
 #include <AIS_InteractiveContext.hxx>
@@ -219,7 +220,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_SymbolPrs, AIS_InteractiveObject);
 std::map<const char*, Handle(Image_AlienPixMap)> SketcherPrs_SymbolPrs::myIconsMap;
 
 
-SketcherPrs_SymbolPrs::SketcherPrs_SymbolPrs(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_SymbolPrs::SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint, 
                                              const std::shared_ptr<GeomAPI_Ax3>& thePlane)
  : AIS_InteractiveObject(), myConstraint(theConstraint), myPlane(thePlane)
 {
@@ -354,8 +355,10 @@ void SketcherPrs_SymbolPrs::ComputeSelection(const Handle(SelectMgr_Selection)&
                                             const Standard_Integer aMode)
 {
   ClearSelected();
-  for (int i = 1; i <= mySPoints.Length(); i++)
-    aSelection->Add(mySPoints.Value(i));
+  if ((aMode == 0) || (aMode == SketcherPrs_Tools::Sel_Constraint)) {
+    for (int i = 1; i <= mySPoints.Length(); i++)
+      aSelection->Add(mySPoints.Value(i));
+  }
 }
 
 
@@ -417,8 +420,10 @@ void SketcherPrs_SymbolPrs::Render(const Handle(OpenGl_Workspace)& theWorkspace)
   theWorkspace->EnableTexture (aTextureBack);
   aCtx->BindProgram (NULL);
 
-  // Update selection position
-  GetContext()->RecomputeSelectionOnly(this);
+  // Update selection position only if there is no selected object
+  // because it can corrupt selection of other objects
+  if ((GetContext()->NbCurrents() == 0) && (GetContext()->NbSelected() == 0))
+    GetContext()->RecomputeSelectionOnly(this);
 }
 
 
index 9145705f520bb787310682d5e9a940d17ac6ebee..446cedabcd6fb9ad28a0d6c11bf2dadae315579b 100644 (file)
@@ -8,6 +8,7 @@
 #define SketcherPrs_SymbolPrs_H
 
 #include "SketcherPrs_SensitivePoint.h"
+#include <ModelAPI_Feature.h>
 
 #include <AIS_InteractiveObject.hxx>
 #include <GeomAPI_Ax3.h>
@@ -22,7 +23,6 @@
 
 #include <OpenGl_Workspace.hxx>
 
-class SketchPlugin_Constraint;
 class OpenGl_Context;
 
 
@@ -38,7 +38,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_SymbolPrs(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_SymbolPrs(ModelAPI_Feature* theConstraint, 
                         const std::shared_ptr<GeomAPI_Ax3>& thePlane);
   
   virtual ~SketcherPrs_SymbolPrs();
@@ -59,7 +59,7 @@ public:
 
   Standard_EXPORT std::shared_ptr<GeomAPI_Ax3> plane() const { return myPlane; }
 
-  Standard_EXPORT SketchPlugin_Constraint* feature() const { return myConstraint; }
+  Standard_EXPORT ModelAPI_Feature* feature() const { return myConstraint; }
 
 
   Handle(Graphic3d_ArrayOfPoints) pointsArray() const { return myPntArray; }
@@ -105,7 +105,7 @@ protected:
 
 protected:
   /// Constraint feature
-  SketchPlugin_Constraint* myConstraint;
+  ModelAPI_Feature* myConstraint;
 
   /// Plane of the current sketcher
   std::shared_ptr<GeomAPI_Ax3> myPlane;
index bbee898f92e735037e25243449d0f4a4991b4497..45f32049425091c54120cc4d9426ca5457d3d15e 100644 (file)
@@ -23,7 +23,7 @@ IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Tangent, SketcherPrs_SymbolPrs);
 
 static Handle(Image_AlienPixMap) MyPixMap;
 
-SketcherPrs_Tangent::SketcherPrs_Tangent(SketchPlugin_Constraint* theConstraint, 
+SketcherPrs_Tangent::SketcherPrs_Tangent(ModelAPI_Feature* theConstraint, 
                                            const std::shared_ptr<GeomAPI_Ax3>& thePlane) 
  : SketcherPrs_SymbolPrs(theConstraint, thePlane)
 {
index 335006da59e1cf682ef42b1167390826a387d561..78aaff550be0a6b1aba32a65701e76325c86ade5 100644 (file)
@@ -8,9 +8,7 @@
 #define SketcherPrs_Tangent_H
 
 #include "SketcherPrs_SymbolPrs.h"
-
-class SketchPlugin_Constraint;
-class SketchPlugin_Sketch;
+#include <ModelAPI_Feature.h>
 
 
 DEFINE_STANDARD_HANDLE(SketcherPrs_Tangent, SketcherPrs_SymbolPrs)
@@ -26,7 +24,7 @@ public:
   /// Constructor
   /// \param theConstraint a constraint feature
   /// \param thePlane a coordinate plane of current sketch
-  Standard_EXPORT SketcherPrs_Tangent(SketchPlugin_Constraint* theConstraint, 
+  Standard_EXPORT SketcherPrs_Tangent(ModelAPI_Feature* theConstraint, 
                                        const std::shared_ptr<GeomAPI_Ax3>& thePlane);
 
   DEFINE_STANDARD_RTTI(SketcherPrs_Tangent)
index c94864db66134292b2ffa075a1329431bdd3ba04..47468899ec7d2d7685b561f1277707b93d5c7bd8 100644 (file)
@@ -20,7 +20,7 @@
 
 namespace SketcherPrs_Tools {
 
-ObjectPtr getResult(SketchPlugin_Constraint* theFeature, const std::string& theAttrName)
+ObjectPtr getResult(ModelAPI_Feature* theFeature, const std::string& theAttrName)
 {
   std::shared_ptr<ModelAPI_Data> aData = theFeature->data();
   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
@@ -40,8 +40,8 @@ std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject)
 }
 
 
-std::shared_ptr<GeomAPI_Pnt2d> getPoint(SketchPlugin_Constraint* theFeature,
-                                               const std::string& theAttribute)
+std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
+                                        const std::string& theAttribute)
 {
   std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
 
@@ -100,30 +100,29 @@ std::shared_ptr<GeomDataAPI_Point2D> getFeaturePoint(DataPtr theData,
 }
 
 //*************************************************************************************
-std::shared_ptr<SketchPlugin_Line> getFeatureLine(DataPtr theData,
-                                                  const std::string& theAttribute)
+FeaturePtr getFeatureLine(DataPtr theData,
+                          const std::string& theAttribute)
 {
-  std::shared_ptr<SketchPlugin_Line> aLine;
+  FeaturePtr aLine;
   if (!theData)
     return aLine;
 
-  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
-      ModelAPI_AttributeRefAttr>(theData->attribute(theAttribute));
+  std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
+    std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theData->attribute(theAttribute));
   if (anAttr) {
     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->object());
     if (aFeature && aFeature->getKind() == SketchPlugin_Line::ID()) {
-      aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aFeature);
+      return aFeature;
     }
   }
   return aLine;
 }
 
 //*************************************************************************************
-std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(
-    const std::shared_ptr<SketchPlugin_Line>& theLine,
-    const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(const FeaturePtr theLine,
+                                                  const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
 {
-  std::shared_ptr<ModelAPI_Data> aData = theLine->data();
+  DataPtr aData = theLine->data();
   std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aData->attribute(SketchPlugin_Line::START_ID()));
   std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
@@ -145,4 +144,4 @@ void setArrowSize(double theSize)
   MyArrowSize = theSize;
 }
 
-};
\ No newline at end of file
+};
index 29446596382d3ccdc54e012871588ec0523fa292..00a2e96630948e82c01f8d29523879ae78e0f760 100644 (file)
 #include <GeomAPI_Shape.h>
 #include <GeomAPI_Pnt2d.h>
 #include <ModelAPI_Object.h>
+#include <ModelAPI_Feature.h>
 #include <string>
 
-class SketchPlugin_Constraint;
-class SketchPlugin_Line;
 class GeomDataAPI_Point2D;
 
 #define MyTextHeight 20
 
 namespace SketcherPrs_Tools {
 
-  SKETCHERPRS_EXPORT ObjectPtr getResult(SketchPlugin_Constraint* theFeature,
-                      const std::string& theAttrName);
+/// Enumeration with modes for activation of selection custom presentations
+enum SelectionModes {
+  /// Start of enumeration
+  Sel_Mode_First = 100, 
+  
+  /// Selection mode for all constraints exclude dimensions
+  Sel_Constraint,
+  
+  /// Selection mode for whole dimension
+  Sel_Dimension_All,
+  
+  /// Selection mode for line of dimension
+  Sel_Dimension_Line,
+
+  /// Selection mode foe text of dimension
+  Sel_Dimension_Text
+};
+
+  SKETCHERPRS_EXPORT ObjectPtr getResult(ModelAPI_Feature* theFeature,
+                                         const std::string& theAttrName);
 
   SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Shape> getShape(ObjectPtr theObject);
 
-  SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getPoint(SketchPlugin_Constraint* theFeature,
+  SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getPoint(ModelAPI_Feature* theFeature,
                                           const std::string& theAttrName);
 
   SKETCHERPRS_EXPORT std::shared_ptr<GeomAPI_Pnt2d> getProjectionPoint(
-                        const std::shared_ptr<SketchPlugin_Line>& theLine,
+                        const FeaturePtr theLine,
                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
 
-  SKETCHERPRS_EXPORT std::shared_ptr<SketchPlugin_Line> getFeatureLine(DataPtr theData,
-                                                    const std::string& theAttribute);
+  SKETCHERPRS_EXPORT FeaturePtr getFeatureLine(DataPtr theData,
+                                               const std::string& theAttribute);
 
   /// Obtain the point object from specified constraint parameter
   SKETCHERPRS_EXPORT std::shared_ptr<GeomDataAPI_Point2D> getFeaturePoint(DataPtr theData,
@@ -45,4 +62,4 @@ namespace SketcherPrs_Tools {
   SKETCHERPRS_EXPORT void setArrowSize(double theSize);
 };
 
-#endif
\ No newline at end of file
+#endif
index 33f1826a792e99d7bcb183d94f35cddb37e78f2d..9e7ce02ae348cfb50ee3f37950e607beb4bfd377 100644 (file)
@@ -128,32 +128,39 @@ void XGUI_ActionsMgr::updateCheckState()
 
 void XGUI_ActionsMgr::updateOnViewSelection()
 {
-  XGUI_Selection* aSelection = myWorkshop->selector()->selection();
-  if (aSelection->getSelected().size() == 0 || !myOperationMgr->hasOperation())
+  if (!myOperationMgr->hasOperation())
     return;
+
   ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
   FeaturePtr anActiveFeature = anOperation->feature();
   if(!anActiveFeature.get())
     return;
-  QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
 
-  SessionPtr aMgr = ModelAPI_Session::get();
-  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
-  foreach(QString aId, nestedCommands(aFeatureId)) {
-    std::list<ModelAPI_Validator*> aValidators;
-    std::list<std::list<std::string> > anArguments;
-    aFactory->validators(aId.toStdString(), aValidators, anArguments);
-    std::list<ModelAPI_Validator*>::iterator aValidator = aValidators.begin();
-    std::list<std::list<std::string> >::iterator aValidatorArgs = anArguments.begin();
-    for (; aValidator != aValidators.end(); aValidator++, aValidatorArgs++) {
-      if (!(*aValidator))
-        continue;
-      const ModuleBase_SelectionValidator* aSelValidator =
-          dynamic_cast<const ModuleBase_SelectionValidator*>(*aValidator);
-      if (!aSelValidator)
-        continue;
-      setActionEnabled(aId, aSelValidator->isValid(aSelection, *aValidatorArgs));
+  QString aFeatureId = QString::fromStdString(anActiveFeature->getKind());
+  XGUI_Selection* aSelection = myWorkshop->selector()->selection();
+  if (aSelection->getSelected().size() == 0) {
+    foreach(QString aId, nestedCommands(aFeatureId)) {
+      setActionEnabled(aId, true);
+    }
+  } else { 
+    SessionPtr aMgr = ModelAPI_Session::get();
+    ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+    foreach(QString aId, nestedCommands(aFeatureId)) {
+      std::list<ModelAPI_Validator*> aValidators;
+      std::list<std::list<std::string> > anArguments;
+      aFactory->validators(aId.toStdString(), aValidators, anArguments);
+      std::list<ModelAPI_Validator*>::iterator aValidator = aValidators.begin();
+      std::list<std::list<std::string> >::iterator aValidatorArgs = anArguments.begin();
+      for (; aValidator != aValidators.end(); aValidator++, aValidatorArgs++) {
+        if (!(*aValidator))
+          continue;
+        const ModuleBase_SelectionValidator* aSelValidator =
+            dynamic_cast<const ModuleBase_SelectionValidator*>(*aValidator);
+        if (!aSelValidator)
+          continue;
+        setActionEnabled(aId, aSelValidator->isValid(aSelection, *aValidatorArgs));
 
+      }
     }
   }
 }
index fef7ed06d1b89a2dfc55d4633ae5ca2ff9bc5446..cbe4bb8fe0235dcd4033d554b039711c6eae0132 100644 (file)
@@ -103,7 +103,7 @@ void XGUI_Displayer::display(ObjectPtr theObject, bool isUpdateViewer)
     GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
     bool isShading = false;
     if (aPrs.get() != NULL) {
-      anAIS = aPrs->getAISObject(AISObjectPtr());
+      anAIS = aPrs->getAISObject(anAIS);
     } else {
       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
       if (aResult.get() != NULL) {
@@ -159,6 +159,8 @@ void XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS,
     }
     aContext->Display(anAISIO, false);
     aContext->SetDisplayMode(anAISIO, isShading? Shading : Wireframe, false);
+    if (isShading)
+      anAISIO->Attributes()->SetFaceBoundaryDraw( Standard_True );
     emit objectDisplayed(theObject, theAIS);
 
     bool isCustomized = customizeObject(theObject);
@@ -791,3 +793,18 @@ bool XGUI_Displayer::customizeObject(ObjectPtr theObject)
   }
   return aCustomPrs->customisePresentation(aResult, anAISObj, myCustomPrs);
 }
+
+
+QColor XGUI_Displayer::setObjectColor(ObjectPtr theObject, const QColor& theColor, bool toUpdate)
+{
+  if (!isVisible(theObject))
+    return Qt::black;
+
+  AISObjectPtr anAISObj = getAISObject(theObject);
+  int aR, aG, aB;
+  anAISObj->getColor(aR, aG, aB);
+  anAISObj->setColor(theColor.red(), theColor.green(), theColor.blue());
+  if (toUpdate)
+    updateViewer();
+  return QColor(aR, aG, aB);
+}
index d0153925ad2cca11b0725bc8c61588ae5575a19f..6811bafdfb13f1850f8749b7af97be2a00db8788 100644 (file)
@@ -27,6 +27,7 @@
 #include <QString>
 #include <QMap>
 #include <QObject>
+#include <QColor>
 
 class ModelAPI_Feature;
 class XGUI_Workshop;
@@ -190,6 +191,12 @@ class XGUI_EXPORT XGUI_Displayer: public QObject
   /// \param theObject object to check
   bool canBeShaded(ObjectPtr theObject) const;
 
+  /// Set color on presentation of an object if it is displayed
+  /// \param theObject an object 
+  /// \param theColor a color which has to be set
+  /// \param theUpdate update viewer flag
+  /// \return previously defined color on the object
+  QColor setObjectColor(ObjectPtr theObject, const QColor& theColor, bool toUpdate = true);
 
 signals:
   /// Signal on object display
index ab9991d503365ecb453e9c9b020e00e6e68d74bd..fdc407f7be5fa95b5a577b800f2748d43d346f16 100644 (file)
@@ -68,7 +68,10 @@ void XGUI_ModuleConnector::activateSubShapesSelection(const QIntList& theTypes)
   // Convert shape types to selection types
   QIntList aModes;
   foreach(int aType, theTypes) {
-    aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum)aType));
+    if (aType > TopAbs_SHAPE) 
+      aModes.append(aType);
+    else
+      aModes.append(AIS_Shape::SelectionMode((TopAbs_ShapeEnum)aType));
   }
   aDisp->activateObjects(aModes);
   //TODO: We have to open Local context because at neutral point filters don't work (bug 25340)
index 5a6992d57646986c588f4211bba049ae6430f571..027248cba7cc970790c1227faadc9975ff867ed2 100644 (file)
@@ -998,6 +998,12 @@ void XGUI_Workshop::onUndo(int theTimes)
 //******************************************************
 void XGUI_Workshop::onRedo(int theTimes)
 {
+  // the viewer update should be blocked in order to avoid the features blinking. For the created
+  // feature a results are created, the flush of the created signal caused the viewer redisplay for
+  // each created result. After a redisplay signal is flushed. So, the viewer update is blocked until
+  // redo of all possible objects happens
+  bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false);
+
   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
   SessionPtr aMgr = ModelAPI_Session::get();
   if (aMgr->isOperation())
@@ -1006,6 +1012,10 @@ void XGUI_Workshop::onRedo(int theTimes)
     aMgr->redo();
   }
   updateCommandStatus();
+
+  // unblock the viewer update functionality and make update on purpose
+  myDisplayer->enableUpdateViewer(isUpdateEnabled);
+  myDisplayer->updateViewer();
 }
 
 //******************************************************