// Author: Artem ZHIDKOV
#include "SketchSolver_Manager.h"
+#include "SketchSolver_Error.h"
#include <Events_Loop.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_Object.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeString.h>
#include <SketchPlugin_Constraint.h>
#include <set>
#include <memory>
+static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+
// Initialization of constraint manager self pointer
SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
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));
+
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
}
SketchSolver_Manager::~SketchSolver_Manager()
void SketchSolver_Manager::processEvent(
const std::shared_ptr<Events_Message>& theMessage)
{
+ checkConflictingConstraints(theMessage);
if (myIsComputed)
return;
myIsComputed = true;
std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
+ bool isUpdateFlushed = stopSendUpdate();
// Shows the message has at least one feature applicable for solver
bool hasProperFeature = false;
}
}
+ bool needToUpdate = false;
// Solve the set of constraints
if (hasProperFeature)
- resolveConstraints(isMovedEvt); // send update for movement in any case
+ needToUpdate = resolveConstraints();
+
+ // Features may be updated => now send events, but for all changed at once
+ if (isUpdateFlushed)
+ allowSendUpdate();
+ // send update for movement in any case
+ if (needToUpdate || isMovedEvt)
+ Events_Loop::loop()->flush(anUpdateEvent);
+
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
break;
if (aFGrIter != aFeatureGroups.end()) {
- std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+ std::list<SketchSolver_Group*> aGroupsToResolve;
+ std::list<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
std::list<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;
+ std::list<SketchSolver_Group*>::iterator aRemoveIt = aGroupIter++;
+ myGroups.erase(aRemoveIt);
continue;
}
if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
(*aGroupIter)->splitGroup(aSeparatedGroups);
+ //if (!(*aGroupIter)->getWorkplane()->string(
+ // SketchPlugin_Sketch::SOLVER_ERROR())->value().empty())
+ aGroupsToResolve.push_back(*aGroupIter);
}
aGroupIter++;
}
- if (aSeparatedGroups.size() > 0)
+ if (aSeparatedGroups.size() > 0) {
myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
+ aGroupsToResolve.insert(aGroupsToResolve.end(),
+ aSeparatedGroups.begin(), aSeparatedGroups.end());
+ }
+
+ if (!aGroupsToResolve.empty())
+ resolveConstraints(aGroupsToResolve);
}
}
myIsComputed = false;
}
+void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr<Events_Message>& theMessage)
+{
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_SOLVER_REPAIRED)) {
+ std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
+ std::dynamic_pointer_cast<ModelAPI_SolverFailedMessage>(theMessage);
+ std::set<ObjectPtr> aSentObjs = aMessage->objects();
+ if (!aSentObjs.empty()) {
+ // Obtain sketch where the constraints are placed.
+ // It is enough to check only one constraint.
+ CompositeFeaturePtr aSketch;
+ FeaturePtr aConstraint = ModelAPI_Feature::feature(*aSentObjs.begin());
+ std::list<SketchSolver_Group*>::const_iterator aGrIt = myGroups.begin();
+ for (; aGrIt != myGroups.end(); ++aGrIt)
+ if ((*aGrIt)->isInteract(aConstraint)) {
+ aSketch = (*aGrIt)->getWorkplane();
+ break;
+ }
+
+ // Search failed groups built on the same sketch
+ if (aSketch) {
+ for (aGrIt = myGroups.begin(); aGrIt != myGroups.end(); ++aGrIt) {
+ SketchSolver_Group* aGroup = *aGrIt;
+ if (aGroup->isBaseWorkplane(aSketch) && aGroup->isFailed() &&
+ !aGroup->isInteract(aConstraint)) {
+ // reset error message on the sketch
+ aGroup->getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(
+ SketchSolver_Error::CONSTRAINTS());
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
// ============================================================================
// Function: changeWorkplane
// Purpose: update workplane by given parameters of the sketch
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;
+ std::list<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
isUpdated = true;
return true;
} else if (aGroups.size() == 1) { // Only one group => add feature into it
GroupID aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ std::list<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)
std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
// Search first group
- std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
+ std::list<SketchSolver_Group*>::iterator aFirstGroupIter;
for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
if ((*aFirstGroupIter)->getId() == *aGroupsIter)
break;
return false;
// Append other groups to the first one
- std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ std::list<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter;
+ ++anOtherGroupIter;
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;
+ anOtherGroupIter = aFirstGroupIter;
+ ++anOtherGroupIter;
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;
+ std::list<SketchSolver_Group*>::iterator aRemoveIt = anOtherGroupIter++;
+ delete *aRemoveIt;
+ myGroups.erase(aRemoveIt);
}
if (aConstraint)
- return (*aFirstGroupIter)->changeConstraint(aConstraint);
- return (*aFirstGroupIter)->updateFeature(theFeature);
+ (*aFirstGroupIter)->changeConstraint(aConstraint);
+ else
+ (*aFirstGroupIter)->updateFeature(theFeature);
+ // groups are merged => need to resolve them
+ return true;
}
// Something goes wrong
// ============================================================================
void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
{
- std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+ bool isMoved = false;
+ std::list<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
for (; aGroupIt != myGroups.end(); aGroupIt++)
- if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+ if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) {
(*aGroupIt)->moveFeature(theFeature);
+ isMoved = true;
+ }
+
+ if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) {
+ // Workaround to move arc.
+ // If the arc has not been constrained, we will push it into empty group and apply movement.
+ for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++)
+ if ((*aGroupIt)->isEmpty())
+ (*aGroupIt)->moveFeature(theFeature);
+ }
}
// ============================================================================
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;
+ std::list<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
if (!(*aGroupIter)->isEmpty())
// Already verified workplanes
std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
- std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+ std::list<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())
// Function: resolveConstraints
// Purpose: change entities according to available constraints
// ============================================================================
-void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate)
+bool SketchSolver_Manager::resolveConstraints(const std::list<SketchSolver_Group*>& theGroups)
{
- //myIsComputed = true;
bool needToUpdate = false;
- static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ const std::list<SketchSolver_Group*>& aGroupsToResolve = theGroups.empty() ? myGroups : theGroups;
+ std::list<SketchSolver_Group*>::const_iterator aGroupIter = aGroupsToResolve.begin();
+ for (; aGroupIter != aGroupsToResolve.end(); aGroupIter++)
+ if ((*aGroupIter)->resolveConstraints())
+ needToUpdate = true;
+ return needToUpdate;
+}
+
+bool SketchSolver_Manager::stopSendUpdate() const
+{
// 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);
}
+ return isUpdateFlushed;
+}
- 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);
+void SketchSolver_Manager::allowSendUpdate() const
+{
+ Events_Loop::loop()->setFlushed(anUpdateEvent, true);
}