#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
+#include <SketchPlugin_Arc.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintDistance.h>
Events_Loop::loop()->send(aMessage);
}
+static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
+{
+ std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
+ std::shared_ptr<ModelAPI_SolverFailedMessage>(
+ new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName)));
+ aMessage->setObjects(theConflicting);
+ Events_Loop::loop()->send(aMessage);
+}
+
// ========================================================
SketchSolver_Group::SketchSolver_Group(
std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
: myID(GroupIndexer::NEW_GROUP()),
- myPrevSolved(true)
+ myPrevResult(STATUS_UNKNOWN)
{
// Initialize workplane
myWorkplaneID = EID_UNKNOWN;
{
myConstraints.clear();
GroupIndexer::REMOVE_GROUP(myID);
+ // send the message that there is no more conflicting constraints
+ if (!myConflictingConstraints.empty()) {
+ sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
+ myConflictingConstraints.clear();
+ }
}
// ============================================================================
if (isEmpty())
return true;
// Check interaction with the storage
- return myStorage->isInteract(theFeature);
+ bool isInteracted = myStorage->isInteract(theFeature);
+ ConstraintConstraintMap::const_iterator anIt = myConstraints.begin();
+ for (; !isInteracted && anIt != myConstraints.end(); ++anIt)
+ if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
+ anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
+ isInteracted = anIt->second->isUsed(theFeature);
+ return isInteracted;
}
// ============================================================================
Events_Error::send(aConstraint->error(), this);
}
myConstraints[theConstraint] = aConstraint;
+
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ notifyCoincidenceChanged(myConstraints[theConstraint]);
}
else
myConstraints[theConstraint]->update();
return true;
}
-
-void SketchSolver_Group::updateConstraints()
+// Update constraints if they contain specific feature
+static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature)
{
- std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
-
- ConstraintConstraintMap::iterator anIt = myConstraints.begin();
- for (; anIt != myConstraints.end(); ++anIt) {
- if (myChangedConstraints.find(anIt->first) == myChangedConstraints.end())
- continue;
- if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
- anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
- aPostponed.insert(anIt->second);
- else
- anIt->second->update();
+ ConstraintConstraintMap::iterator aCIt = theConstraints.begin();
+ for (; aCIt != theConstraints.end(); ++aCIt) {
+ SketchSolver_ConstraintType aType = aCIt->second->getType();
+ if ((aType == CONSTRAINT_MULTI_ROTATION ||
+ aType == CONSTRAINT_MULTI_TRANSLATION)
+ && aCIt->second->isUsed(theFeature))
+ std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
+ else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE ||
+ aType == CONSTRAINT_SYMMETRIC || aType == CONSTRAINT_ANGLE)
+ && aCIt->second->isUsed(theFeature))
+ aCIt->second->update();
}
-
- // Update postponed constraints
- std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
- for (; aSCIter != aPostponed.end(); ++aSCIter)
- (*aSCIter)->update();
-
- myChangedConstraints.clear();
}
-static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature)
+// Recalculate slave features of the Multi constraints
+static void updateMultiConstraints(ConstraintConstraintMap& theConstraints)
{
ConstraintConstraintMap::iterator aCIt = theConstraints.begin();
for (; aCIt != theConstraints.end(); ++aCIt) {
- if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
- aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
- && aCIt->second->isUsed(theFeature))
+ SketchSolver_ConstraintType aType = aCIt->second->getType();
+ if ((aType == CONSTRAINT_MULTI_ROTATION ||
+ aType == CONSTRAINT_MULTI_TRANSLATION))
std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
}
}
// Secondly, search attributes of the feature in the list of the Multi constraints and update them
updateMultiConstraints(myConstraints, theFeature);
+
+ // Workaround to process arcs.
+ // When move unconstrained arc, add temporary constraint to fix radius.
+ if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
+ bool hasDup = myStorage->hasDuplicatedConstraint();
+ SolverConstraintPtr aFixedRadius = aBuilder->createFixedArcRadiusConstraint(theFeature);
+ if (aFixedRadius) {
+ aFixedRadius->process(myStorage, getId(), getWorkplaneId());
+ hasDup = myStorage->hasDuplicatedConstraint() && !hasDup;
+ if (aFixedRadius->error().empty() && !hasDup)
+ setTemporary(aFixedRadius);
+ else
+ aFixedRadius->remove();
+ }
+ }
}
// ============================================================================
// ============================================================================
bool SketchSolver_Group::resolveConstraints()
{
- if (!myChangedConstraints.empty())
- updateConstraints();
-
bool aResolved = false;
- bool isGroupEmpty = isEmpty();
+ bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
if (myStorage->isNeedToResolve() && !isGroupEmpty) {
if (!mySketchSolver)
mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
aResult = mySketchSolver->solve();
if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
break;
- // try to update parameters and resolve once again
- ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
- for (; aConstrIt != myConstraints.end(); ++aConstrIt)
- aConstrIt->second->update();
+//// // try to update parameters and resolve once again
+//// ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
+//// for (; aConstrIt != myConstraints.end(); ++aConstrIt)
+//// aConstrIt->second->update();
isLastChance = true;
removeTemporaryConstraints();
} catch (...) {
// Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
- if (myPrevSolved) {
+ if (myPrevResult == STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
// the error message should be changed before sending the message
sendMessage(EVENT_SOLVER_FAILED);
- myPrevSolved = false;
+ myPrevResult = STATUS_FAILED;
}
mySketchSolver->undo();
return false;
}
if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes
myStorage->refresh();
- if (!myPrevSolved) {
+ updateMultiConstraints(myConstraints);
+ if (myPrevResult != STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
// the error message should be changed before sending the message
- sendMessage(EVENT_SOLVER_REPAIRED);
- myPrevSolved = true;
+ sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
+ myConflictingConstraints.clear();
+ myPrevResult = STATUS_OK;
}
} else {
mySketchSolver->undo();
if (!myConstraints.empty()) {
-// Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
+ // the error message should be changed before sending the message
getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
- if (myPrevSolved) {
- // the error message should be changed before sending the message
- sendMessage(EVENT_SOLVER_FAILED);
- myPrevSolved = false;
+ if (myPrevResult != aResult || myPrevResult == STATUS_UNKNOWN) {
+ // Obtain list of conflicting constraints
+ std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
+
+ if (myConflictingConstraints.empty())
+ sendMessage(EVENT_SOLVER_FAILED, aConflicting);
+ else {
+ std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
+ for (; anIt != aConflicting.end(); ++anIt)
+ myConflictingConstraints.erase(*anIt);
+ if (!myConflictingConstraints.empty()) {
+ // some constraints does not conflict, send corresponding message
+ sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
+ }
+ }
+ myConflictingConstraints = aConflicting;
+ myPrevResult = aResult;
}
}
}
for (; aCIter != myConstraints.end(); aCIter++)
if (aCIter->first == theConstraint) {
aCIter->second->remove(); // the constraint is not fully removed
+ if (aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ notifyCoincidenceChanged(aCIter->second);
break;
}
if (aCIter != myConstraints.end())
myConstraints.erase(aCIter);
}
-// ============================================================================
-// Function: isComplexConstraint
-// Class: SketchSolver_Group
-// Purpose: verifies the constraint is complex, i.e. it needs another constraints to be created before
-// ============================================================================
-bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
-{
- return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
- theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
- theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
-}
-
// ============================================================================
// Function: setTemporary
// Class: SketchSolver_Group
return aResult;
}
+void SketchSolver_Group::notifyCoincidenceChanged(SolverConstraintPtr theCoincidence)
+{
+ const std::list<EntityWrapperPtr>& aCoincident = theCoincidence->attributes();
+ EntityWrapperPtr anAttr1 = aCoincident.front();
+ EntityWrapperPtr anAttr2 = aCoincident.back();
+
+ ConstraintConstraintMap::iterator anIt = myConstraints.begin();
+ for (; anIt != myConstraints.end(); ++anIt)
+ anIt->second->notifyCoincidenceChanged(anAttr1, anAttr2);
+}