]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/SketchSolver/SketchSolver_ConstraintManager.cpp
Salome HOME
Issue #604 Creation of an unexpected line in the Sketcher
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintManager.cpp
index 86cb8bacd457dd4feef778ce8148fa9b7b6698f3..4034c0b7e0558355b0f2f976e6ea753d8b8aa13b 100644 (file)
@@ -1,25 +1,63 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
 // File:    SketchSolver_ConstraintManager.cpp
 // Created: 08 May 2014
 // Author:  Artem ZHIDKOV
 
 #include "SketchSolver_ConstraintManager.h"
 
+#include <Events_Loop.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Attribute.h>
+
 #include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintDistance.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>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+#include <SketchPlugin_Feature.h>
+
+#include <list>
+#include <set>
+#include <memory>
 
+// Initialization of constraint manager self pointer
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
 
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
+/// Global constraint manager object
+SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
 
 // ========================================================
 // ========= SketchSolver_ConstraintManager ===============
 // ========================================================
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
+{
+  if (!_self)
+    _self = new SketchSolver_ConstraintManager();
+  return _self;
+}
+
 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
 {
   myGroups.clear();
+  myIsComputed = false;
+
+  // Register in event loop
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -27,167 +65,328 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
   myGroups.clear();
 }
 
-void SketchSolver_ConstraintManager::findGroups(
-              boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
-              std::vector<Slvs_hGroup>&                  theGroupIDs) const
+// ============================================================================
+//  Function: processEvent
+//  Class:    SketchSolver_Session
+//  Purpose:  listen the event loop and process the message
+// ============================================================================
+void SketchSolver_ConstraintManager::processEvent(
+  const std::shared_ptr<Events_Message>& theMessage)
 {
-  std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
-  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
-    if (aGroupIter->isInteract(theConstraint))
-      theGroupIDs.push_back(aGroupIter->getId());
-}
+  if (myIsComputed)
+    return;
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
+      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
+      || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
+    std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+        std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+    std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
 
+    // Shows the message has at least one feature applicable for solver
+    bool hasProperFeature = false;
 
-// ========================================================
-// =========  SketchSolver_ConstraintGroup  ===============
-// ========================================================
+    bool isMovedEvt = theMessage->eventID()
+        == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
+    if (isMovedEvt) {
+      std::set<ObjectPtr>::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+        std::shared_ptr<SketchPlugin_Feature> aSFeature = 
+            std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+        if (aSFeature) {
+          moveEntity(aSFeature);
+          hasProperFeature = true;
+        }
+      }
+    } else {
+      std::set<ObjectPtr>::iterator aFeatIter;
+      // iterate sketchers fisrt to create all sketches before (on load may exist several sketches)
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+        FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
+        if (!aFeature)
+          continue;
+        const std::string& aFeatureKind = aFeature->getKind();
+        if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0) {
+          std::shared_ptr<ModelAPI_CompositeFeature> aSketch = std::dynamic_pointer_cast<
+              ModelAPI_CompositeFeature>(aFeature);
+          hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
+        }
+      }
+      // then get anything but not the sketch
+      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)
+          continue;
+        if (aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
+          continue; // skip Fillet features
+        if (SketchSolver_Group::isComplexConstraint(aFeature)) {
+          aComplexConstraints.insert(aFeature);
+          continue;
+        }
+        hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature;
+      }
+      // 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)
+          continue;
+        hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature;
+      }
+    }
 
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup()
-  : myID(++myGroupIndexer),
-    myParamMaxID(0),
-    myEntityMaxID(0),
-    myConstrMaxID(0),
-    myConstraintMap()
-{
-  myParams.clear();
-  myEntities.clear();
-  myConstraints.clear();
-
-  // The workplane will be initialized on first constraint, so its handle is NULL meanwhile
-  myWorkplane.h = 0;
-
-  // Nullify all elements of the set of equations
-  myConstrSet.param = 0;
-  myConstrSet.entity = 0;
-  myConstrSet.constraint = 0;
-  myConstrSet.failed = 0;
-}
+    // Solve the set of constraints
+    if (hasProperFeature)
+      resolveConstraints(isMovedEvt); // send update for movement in any case
+  } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
+    std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
+        std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
+    const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
 
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
-  myParams.clear();
-  myEntities.clear();
-  myConstraints.clear();
-  myConstraintMap.clear();
-
-  if (myConstrSet.param)
-    delete [] myConstrSet.param;
-  if (myConstrSet.entity)
-    delete [] myConstrSet.entity;
-  if (myConstrSet.constraint)
-    delete [] myConstrSet.constraint;
-  if (myConstrSet.failed)
-    delete [] myConstrSet.failed;
+    // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
+    std::set<std::string>::const_iterator aFGrIter;
+    for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+      if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
+          aFGrIter->compare(ModelAPI_Feature::group()) == 0)
+        break;
+
+    if (aFGrIter != aFeatureGroups.end()) {
+      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;
+          int aShift = aGroupIter - myGroups.begin();
+          myGroups.erase(aGroupIter);
+          aGroupIter = myGroups.begin() + aShift;
+          continue;
+        }
+        if (!(*aGroupIter)->isConsistent()) {  // some constraints were removed, try to split the group
+          (*aGroupIter)->splitGroup(aSeparatedGroups);
+        }
+        aGroupIter++;
+      }
+      if (aSeparatedGroups.size() > 0)
+        myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
+    }
+  }
 }
 
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
-                boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
+// ============================================================================
+//  Function: changeWorkplane
+//  Class:    SketchSolver_Session
+//  Purpose:  update workplane by given parameters of the sketch
+// ============================================================================
+bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
 {
-  /// \todo Should be implemented
-  return false;
+  bool aResult = true;  // changed when a workplane wrongly updated
+  bool isUpdated = false;
+  // Try to update specified workplane in all groups
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
+      isUpdated = true;
+      if (!(*aGroupIter)->updateWorkplane())
+        aResult = false;
+    }
+  // If the workplane is not updated, so this is a new workplane
+  if (!isUpdated) {
+    SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
+    // Verify that the group is created successfully
+    if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
+      delete aNewGroup;
+      return false;
+    }
+    myGroups.push_back(aNewGroup);
+  }
+  return aResult;
 }
 
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
-                boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
+// ============================================================================
+//  Function: changeConstraintOrEntity
+//  Class:    SketchSolver_Session
+//  Purpose:  create/update the constraint or the feature and place it into appropriate group
+// ============================================================================
+bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
+    std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  if (myWorkplane.h == 0)
-  {
-    // Create workplane when first constraint is added
-    std::list< boost::shared_ptr<ModelAPI_Attribute> > aWPAttr;
-    theConstraint->getSketchParameters(aWPAttr);
-    if (!addWorkplane(aWPAttr))
+  // Search the groups which this feature touches
+  std::set<Slvs_hGroup> aGroups;
+  findGroups(theFeature, aGroups);
+
+  std::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+
+  // Process the groups list
+  if (aGroups.size() == 0) {
+    // There are no groups applicable for this constraint => create new one
+    // The group will be created only for constraints, not for features
+    if (!aConstraint) return false;
+    std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
+    if (!aWP)
+      return false;
+    SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
+    if (!aGroup->changeConstraint(aConstraint)) {
+      delete aGroup;
+      return false;
+    }
+    myGroups.push_back(aGroup);
+    return true;
+  } else if (aGroups.size() == 1) {  // Only one group => add feature into it
+    Slvs_hGroup aGroupId = *(aGroups.begin());
+    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)->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_Group*>::iterator aFirstGroupIter;
+    for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
+      if ((*aFirstGroupIter)->getId() == *aGroupsIter)
+        break;
+    if (aFirstGroupIter == myGroups.end())
       return false;
+
+    // Append other groups to the first one
+    std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+    for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
+      for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
+        if ((*anOtherGroupIter)->getId() == *aGroupsIter)
+          break;
+      if (anOtherGroupIter == myGroups.end()) {  // Group disappears
+        anOtherGroupIter = aFirstGroupIter + 1;
+        continue;
+      }
+
+      (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
+      int aShiftFirst = aFirstGroupIter - myGroups.begin();
+      int aShiftOther = anOtherGroupIter - myGroups.begin();
+      delete *anOtherGroupIter;
+      myGroups.erase(anOtherGroupIter);
+      aFirstGroupIter = myGroups.begin() + aShiftFirst;
+      anOtherGroupIter = myGroups.begin() + aShiftOther;
+    }
+
+    if (aConstraint)
+      return (*aFirstGroupIter)->changeConstraint(aConstraint);
+    return (*aFirstGroupIter)->updateFeature(theFeature);
   }
 
-  // Create constraint parameters
-  double aDistance = 0.0; // scalar value of the constraint
-  boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
-    boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-  if (aDistAttr.get())
-    aDistance = aDistAttr->value();
-
-  Slvs_hEntity aPtA, aPtB, aEntityA, aEntityB; // parameters of the constraint
-  boost::shared_ptr<ModelAPI_Attribute> aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_A);
-  aPtA = addEntity(aEntAttr);
-  if (aPtA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_B);
-  aPtB = addEntity(aEntAttr);
-  if (aPtB == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-  aEntityA = addEntity(aEntAttr);
-  if (aEntityA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-  aEntityB = addEntity(aEntAttr);
-  if (aEntityB == 0) return false;
-
-  // Constraint type
-  int aConstrType = getConstraintType(theConstraint);
-  if (aConstrType == 0) return false;
-
-  // Create SolveSpace constraint structure
-  Slvs_Constraint aConstraint = 
-    Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, 
-                        aDistance, aPtA, aPtB, aEntityA, aEntityB);
-  myConstraints.push_back(aConstraint);
-  myConstraintMap[theConstraint] = *(myConstraints.rbegin());
-
-  return true;
+  // Something goes wrong
+  return false;
 }
 
-Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
-                boost::shared_ptr<ModelAPI_Attribute> theEntity)
+// ============================================================================
+//  Function: moveEntity
+//  Class:    SketchSolver_Session
+//  Purpose:  update element moved on the sketch, which is used by constraints
+// ============================================================================
+void SketchSolver_ConstraintManager::moveEntity(
+    std::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  /// \todo Should be implemented
-  return 0;
+  std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+  for (; aGroupIt != myGroups.end(); aGroupIt++)
+    if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+      (*aGroupIt)->moveFeature(theFeature);
 }
 
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
-                std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams)
+// ============================================================================
+//  Function: findGroups
+//  Class:    SketchSolver_Session
+//  Purpose:  search groups of entities interacting with given feature
+// ============================================================================
+void SketchSolver_ConstraintManager::findGroups(
+    std::shared_ptr<SketchPlugin_Feature> theFeature,
+    std::set<Slvs_hGroup>& theGroupIDs) const
 {
-  /// \todo Should be implemented
-  return false;
+  std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
+
+  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())
+        theGroupIDs.insert((*aGroupIter)->getId());
+      else if (!anEmptyGroup)
+        anEmptyGroup = *aGroupIter;
+    }
+
+  // When only empty group is found, use it
+  if (anEmptyGroup && theGroupIDs.empty())
+    theGroupIDs.insert(anEmptyGroup->getId());
 }
 
-int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
-                const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
+// ============================================================================
+//  Function: findWorkplane
+//  Class:    SketchSolver_Session
+//  Purpose:  search workplane containing given feature
+// ============================================================================
+std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
+::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
 {
-  if (theConstraint->getKind() == SketchPlugin_ConstraintDistance().getKind())
-  {
-    boost::shared_ptr<ModelAPI_Attribute> aPtA  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_A);
-    boost::shared_ptr<ModelAPI_Attribute> aPtB  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_B);
-    boost::shared_ptr<ModelAPI_Attribute> aEntA = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-    boost::shared_ptr<ModelAPI_Attribute> aEntB = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-    boost::shared_ptr<ModelAPI_AttributeDouble> aDistance = 
-      boost::shared_dynamic_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-    if (aPtA.get()) // ptA is an attribute of the constraint
-    {
-//      if (aEntA.get()) // entityA is an attribute of the constraint
-//      {
-//        if (aEntA->feature()->getKind() == SketchPlugin_Line().getKind()) // entityA is a line
-//        {
-//          if (aEntB.get() && aEntB->feature()->getKind() == SketchPlugin_Line().getKind()) // entityB is a line too
-//            return SLVS_C_ANGLE;
-//          else if (aPtB.get()) // ptB is also an attribute of the constraint
-//            return SLVS_C_PROJ_PT_DISTANCE;
-//          else
-//            return SLVS_C_PT_LINE_DISTANCE;
-//        }
-//        /// \todo Implement other point-entity distances
-//      }
-//      else 
-      if (aPtB.get()) // ptB is an attribute of the constrtaint => point-point distance
-      {
-        if (aDistance->value() == 0.0)
-          return SLVS_C_POINTS_COINCIDENT;
-        else 
-          return SLVS_C_PT_PT_DISTANCE;
-      }
+  // Already verified workplanes
+  std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
+
+  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())
+      continue;
+
+    DataPtr aData = aWP->data();
+    if (aData->isValid()) {
+      std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
+          ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
+      std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
+      std::list<ObjectPtr>::const_iterator anIter;
+      for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+        if (*anIter == theFeature)
+          return aWP;  // workplane is found
     }
-    else if (aEntA.get() && !aEntB.get() && !aPtB.get())
-      return SLVS_C_DIAMETER;
-    return SLVS_C_UNKNOWN;
+    aVerified.insert(aWP);
   }
-  /// \todo Implement other kind of constrtaints
 
-  return SLVS_C_UNKNOWN;
+  return std::shared_ptr<ModelAPI_CompositeFeature>();
+}
+
+// ============================================================================
+//  Function: resolveConstraints
+//  Class:    SketchSolver_Session
+//  Purpose:  change entities according to available constraints
+// ============================================================================
+void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdate)
+{
+  myIsComputed = true;
+  bool needToUpdate = false;
+  static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+  // to avoid redisplay of each segment on update by solver one by one in the viewer
+  bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+  if (isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+  }
+
+  std::vector<SketchSolver_Group*>::iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if ((*aGroupIter)->resolveConstraints())
+      needToUpdate = true;
+
+  // Features may be updated => now send events, but for all changed at once
+  if (isUpdateFlushed) {
+    Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+  }
+  // Must be before flush because on "Updated" flush the results may be produced
+  // and the creation event is appeared with many new objects. If myIsComputed these
+  // events are missed in processEvents and some elements are not added.
+  myIsComputed = false;
+  if (needToUpdate || theForceUpdate)
+    Events_Loop::loop()->flush(anUpdateEvent);
 }