#include <SketchSolver_Error.h>
#include <SketchSolver_Manager.h>
-#include <Events_Error.h>
+#include <Events_InfoMessage.h>
#include <Events_Loop.h>
#include <ModelAPI_AttributeString.h>
#include <ModelAPI_Events.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
#include <SketchPlugin_ConstraintRadius.h>
#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintSplit.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MultiRotation.h>
{
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);
+ if (isInteracted)
+ break;
+ // if theFeature is a constraint, check its attributes
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+ if (!aConstraint)
+ continue;
+ for (int i = 0; i < 4 && !isInteracted; ++i) {
+ AttributeRefAttrPtr aRefAttr = aConstraint->refattr(aConstraint->ATTRIBUTE(i));
+ if (!aRefAttr)
+ continue;
+ isInteracted = anIt->second->isUsed((AttributePtr)aRefAttr);
+ }
+ }
+ return isInteracted;
}
// ============================================================================
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);
+ Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send();
}
myConstraints[theConstraint] = aConstraint;
+
+ if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ notifyCoincidenceChanged(myConstraints[theConstraint]);
}
else
myConstraints[theConstraint]->update();
return true;
}
+// Update constraints if they contain specific feature
static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature)
{
ConstraintConstraintMap::iterator aCIt = theConstraints.begin();
for (; aCIt != theConstraints.end(); ++aCIt) {
- if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
- aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
+ 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_TANGENT_ARC_ARC ||
+ aType == CONSTRAINT_SYMMETRIC || aType == CONSTRAINT_ANGLE)
+ && aCIt->second->isUsed(theFeature))
+ aCIt->second->update();
+ }
+}
+
+// Recalculate slave features of the Multi constraints
+static void updateMultiConstraints(ConstraintConstraintMap& theConstraints)
+{
+ 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))
+ std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
}
}
return isUpdated;
}
-void SketchSolver_Group::moveFeature(FeaturePtr theFeature)
+bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
{
BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
myStorage->blockEvents(true);
myStorage->refresh(true);
+ // Secondly, search attributes of the feature in the list of the Multi constraints and update them
+ updateMultiConstraints(myConstraints, theFeature);
+
// Then, create temporary Fixed constraint
SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
if (!aConstraint)
- return;
+ return false;
aConstraint->process(myStorage, getId(), getWorkplaneId());
if (aConstraint->error().empty())
setTemporary(aConstraint);
- // 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());
- if (aFixedRadius->error().empty())
+ hasDup = myStorage->hasDuplicatedConstraint() && !hasDup;
+ if (aFixedRadius->error().empty() && !hasDup)
setTemporary(aFixedRadius);
+ else
+ aFixedRadius->remove();
}
}
+ return true;
}
// ============================================================================
{
bool aResolved = false;
bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
- if (myStorage->isNeedToResolve() && !isGroupEmpty) {
+ if (myStorage->isNeedToResolve() &&
+ (!isGroupEmpty || !myConflictingConstraints.empty() || myPrevResult == STATUS_FAILED)) {
if (!mySketchSolver)
mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
try {
if (myStorage->hasDuplicatedConstraint())
aResult = STATUS_INCONSISTENT;
- else {
+ else if (!isGroupEmpty) {
// To avoid overconstraint situation, we will remove temporary constraints one-by-one
// and try to find the case without overconstraint
bool isLastChance = false;
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());
+ getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
+ ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
if (myPrevResult == STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
// the error message should be changed before sending the message
sendMessage(EVENT_SOLVER_FAILED);
mySketchSolver->undo();
return false;
}
- if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes
+ // solution succeeded, store results into correspondent attributes
+ if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {
+ myStorage->setNeedToResolve(false);
myStorage->refresh();
+ updateMultiConstraints(myConstraints);
+ // multi-constraints updated some parameters, need to store them
+ if (myStorage->isNeedToResolve())
+ resolveConstraints();
+
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);
+ std::set<ObjectPtr> aConflicting = myConflictingConstraints;
+ myConflictingConstraints.clear();
myPrevResult = STATUS_OK;
+ // the error message should be changed before sending the message
+ sendMessage(EVENT_SOLVER_REPAIRED, aConflicting);
}
} else {
mySketchSolver->undo();
if (!myConstraints.empty()) {
-// Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
- getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
- if (myPrevResult != aResult || myPrevResult == STATUS_UNKNOWN) {
+ // the error message should be changed before sending the message
+ getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
+ ->setValue(SketchSolver_Error::CONSTRAINTS());
+ if (myPrevResult != aResult ||
+ myPrevResult == STATUS_UNKNOWN ||
+ myPrevResult == STATUS_FAILED) {
// Obtain list of conflicting constraints
std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
- // the error message should be changed before sending the message
- sendMessage(EVENT_SOLVER_FAILED, aConflicting);
+ if (!myConflictingConstraints.empty()) {
+ 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;
+ if (!myConflictingConstraints.empty())
+ sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
myPrevResult = aResult;
}
}
aResolved = true;
} else if (!isGroupEmpty) {
- // Check there are constraints Fixed. If they exist, update parameters by stored values
+ // Check if the group contains only constraints Fixed, update parameters by stored values
+ aResolved = true;
ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
for (; aCIt != myConstraints.end(); ++aCIt)
- if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
- aResolved = true;
+ if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
+ aResolved = false;
break;
}
- if (aCIt != myConstraints.end())
+ if (aCIt == myConstraints.end())
myStorage->refresh();
}
removeTemporaryConstraints();
{
// New storage will be used in trimmed way to store the list of constraint interacted together.
StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
- std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
+ // empty vector to avoid creation of solver's constraints
+ std::list<ConstraintWrapperPtr> aDummyVec;
// Obtain constraints, which should be separated
std::list<ConstraintPtr> anUnusedConstraints;
anUnusedConstraints.push_back(aCIter->first);
}
- // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
+ // Check the unused constraints once again,
+ // because they may become interacted with new storage since adding constraints
std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
while (aUnuseIt != anUnusedConstraints.end()) {
if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
}
std::list<SketchSolver_Group*>::iterator aCutsIter;
- aUnuseIt = anUnusedConstraints.begin();
- for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
- // Remove unused constraints
+ // Remove unused constraints
+ for (aUnuseIt = anUnusedConstraints.begin(); aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt)
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()) {
+
+ SketchSolver_Group* aBaseGroup;
+ for (aUnuseIt = anUnusedConstraints.begin(); aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
+ aBaseGroup = 0;
+ aCutsIter = theCuts.begin();
+ // Try to append constraint to the current group
+ if (isInteract(*aUnuseIt)) {
+ changeConstraint(*aUnuseIt);
+ aBaseGroup = this;
+ } else {
+ // Try to append constraint to already existent group
+ for (; aCutsIter != theCuts.end(); ++aCutsIter)
+ if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+ (*aCutsIter)->changeConstraint(*aUnuseIt);
+ break;
+ }
+ }
+
+ if (aCutsIter == theCuts.end() && !aBaseGroup) {
// Add new group
SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
aGroup->changeConstraint(*aUnuseIt);
theCuts.push_back(aGroup);
} else {
+ if (!aBaseGroup)
+ aBaseGroup = *aCutsIter++;
// Find other groups interacting with constraint
- std::list<SketchSolver_Group*>::iterator aBaseGroupIt = aCutsIter;
- for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter)
+ for (; aCutsIter != theCuts.end(); ++aCutsIter)
if ((*aCutsIter)->isInteract(*aUnuseIt)) {
- (*aBaseGroupIt)->mergeGroups(**aCutsIter);
+ aBaseGroup->mergeGroups(**aCutsIter);
std::list<SketchSolver_Group*>::iterator aRemoveIt = aCutsIter--;
theCuts.erase(aRemoveIt);
}
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);
+ // empty group => clear storage
+ if (myConstraints.empty()) {
+ myStorage = StoragePtr();
+ mySketchSolver = SolverPtr();
+ updateWorkplane();
+ }
}
// ============================================================================
AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
if (anAttrA && anAttrB && (anAttrA->isObject() || anAttrB->isObject()))
- return 2.0; // point-on-line and point-on-circle should go before points coincidence constraint
+ // point-on-line and point-on-circle should go before points coincidence constraint
+ return 2.0;
return 2.5;
}
if (anID == SketchPlugin_ConstraintDistance::ID() ||
anID == SketchPlugin_ConstraintMirror::ID())
return 6.0;
if (anID == SketchPlugin_ConstraintRigid::ID())
- return 7.0;
+ return 0.5;
if (anID == SketchPlugin_MultiRotation::ID() ||
anID == SketchPlugin_MultiTranslation::ID())
return 8.0;
return featureToVal(theFeature1) < featureToVal(theFeature2);
}
-std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
+std::list<FeaturePtr> SketchSolver_Group::
+ selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
{
std::list<FeaturePtr> aResult;
std::list<FeaturePtr>::iterator aResIt;
std::set<ObjectPtr>::const_iterator anObjIter = theObjects.begin();
for (; anObjIter != theObjects.end(); ++anObjIter) {
// Operate sketch itself and SketchPlugin features only.
- // Also, the Fillet need to be skipped, because there are several separated constraints composing it.
+ // Also, the Fillet and Split need to be skipped,
+ // because there are several separated constraints composing it.
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
if (!aFeature)
continue;
std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) ||
- aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
+ aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() ||
+ aFeature->getKind() == SketchPlugin_ConstraintSplit::ID())
continue;
// Find the place where to insert a feature
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);
+}