X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=867775e50d2301b9defd228c2831157cfe4c37a8;hb=7c2abb57ebb622471f232495cf6b6afda0702c59;hp=c2034c1576d3f703cda07d094aedd0db8721c458;hpb=ca7211a274ba4dc99bd469ca44dd072fcb517dee;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index c2034c157..867775e50 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -130,8 +131,21 @@ bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const 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()) + 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(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; } @@ -166,9 +180,12 @@ bool SketchSolver_Group::changeConstraint( 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(); @@ -193,6 +210,7 @@ bool SketchSolver_Group::changeConstraint( return true; } +// Update constraints if they contain specific feature static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature) { ConstraintConstraintMap::iterator aCIt = theConstraints.begin(); @@ -202,13 +220,25 @@ static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, Feat aType == CONSTRAINT_MULTI_TRANSLATION) && aCIt->second->isUsed(theFeature)) std::dynamic_pointer_cast(aCIt->second)->update(true); - else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE || - aType == CONSTRAINT_SYMMETRIC) + 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(aCIt->second)->update(true); + } +} + bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) { if (!checkFeatureValidity(theFeature)) @@ -230,7 +260,7 @@ bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) return isUpdated; } -void SketchSolver_Group::moveFeature(FeaturePtr theFeature) +bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) { BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); @@ -238,27 +268,32 @@ void SketchSolver_Group::moveFeature(FeaturePtr theFeature) 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; } // ============================================================================ @@ -308,7 +343,8 @@ bool SketchSolver_Group::resolveConstraints() { 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(); @@ -321,7 +357,7 @@ bool SketchSolver_Group::resolveConstraints() 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; @@ -342,7 +378,8 @@ bool SketchSolver_Group::resolveConstraints() } } 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); @@ -351,27 +388,36 @@ bool SketchSolver_Group::resolveConstraints() 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, myConflictingConstraints); + std::set 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()) { // 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) { + 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 aConflicting = myStorage->getConflictingConstraints(mySketchSolver); - if (myConflictingConstraints.empty()) - sendMessage(EVENT_SOLVER_FAILED, aConflicting); - else { + if (!myConflictingConstraints.empty()) { std::set::iterator anIt = aConflicting.begin(); for (; anIt != aConflicting.end(); ++anIt) myConflictingConstraints.erase(*anIt); @@ -381,6 +427,8 @@ bool SketchSolver_Group::resolveConstraints() } } myConflictingConstraints = aConflicting; + if (!myConflictingConstraints.empty()) + sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints); myPrevResult = aResult; } } @@ -388,14 +436,15 @@ bool SketchSolver_Group::resolveConstraints() 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(); @@ -428,6 +477,11 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) continue; changeConstraint(aConstr); } + + // merge previous states of groups => use the worst state, + // so the group after rebuilt may discard error messages if exist + if (theGroup.myPrevResult > myPrevResult) + myPrevResult = theGroup.myPrevResult; } // ============================================================================ @@ -439,7 +493,8 @@ void SketchSolver_Group::splitGroup(std::list& theCuts) { // 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 aDummyVec; // empty vector to avoid creation of solver's constraints + // empty vector to avoid creation of solver's constraints + std::list aDummyVec; // Obtain constraints, which should be separated std::list anUnusedConstraints; @@ -451,7 +506,8 @@ void SketchSolver_Group::splitGroup(std::list& theCuts) 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::iterator aUnuseIt = anUnusedConstraints.begin(); while (aUnuseIt != anUnusedConstraints.end()) { if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) { @@ -464,27 +520,39 @@ void SketchSolver_Group::splitGroup(std::list& theCuts) } std::list::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::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::iterator aRemoveIt = aCutsIter--; theCuts.erase(aRemoveIt); } @@ -561,10 +629,18 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) 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(); + } } // ============================================================================ @@ -612,7 +688,8 @@ static double featureToVal(FeaturePtr theFeature) AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast( 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() || @@ -632,7 +709,7 @@ static double featureToVal(FeaturePtr theFeature) 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; @@ -646,7 +723,8 @@ static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2) return featureToVal(theFeature1) < featureToVal(theFeature2); } -std::list SketchSolver_Group::selectApplicableFeatures(const std::set& theObjects) +std::list SketchSolver_Group:: + selectApplicableFeatures(const std::set& theObjects) { std::list aResult; std::list::iterator aResIt; @@ -654,14 +732,16 @@ std::list SketchSolver_Group::selectApplicableFeatures(const std::se std::set::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(*anObjIter); if (!aFeature) continue; - std::shared_ptr aSketchFeature = + std::shared_ptr aSketchFeature = std::dynamic_pointer_cast(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 @@ -674,3 +754,13 @@ std::list SketchSolver_Group::selectApplicableFeatures(const std::se return aResult; } +void SketchSolver_Group::notifyCoincidenceChanged(SolverConstraintPtr theCoincidence) +{ + const std::list& 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); +}