X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=a39aab6e6a535330fec2df414fbec7dfc3e6fd19;hb=c040abb8ae7ecff3c1b7d0dd97a9bf88972df93c;hp=ee4c2da05af6786761270d0ca593a3c23daec76e;hpb=5e375c5660d4b81449e6a3dae671d1d890f01139;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index ee4c2da05..a39aab6e6 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -12,13 +12,14 @@ #include #include -#include +#include #include #include #include #include #include +#include #include #include #include @@ -68,6 +69,15 @@ static void sendMessage(const char* theMessageName) Events_Loop::loop()->send(aMessage); } +static void sendMessage(const char* theMessageName, const std::set& theConflicting) +{ + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName))); + aMessage->setObjects(theConflicting); + Events_Loop::loop()->send(aMessage); +} + // ======================================================== @@ -77,7 +87,7 @@ static void sendMessage(const char* theMessageName) SketchSolver_Group::SketchSolver_Group( std::shared_ptr theWorkplane) : myID(GroupIndexer::NEW_GROUP()), - myPrevSolved(true) + myPrevResult(STATUS_UNKNOWN) { // Initialize workplane myWorkplaneID = EID_UNKNOWN; @@ -88,6 +98,11 @@ SketchSolver_Group::~SketchSolver_Group() { 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(); + } } // ============================================================================ @@ -111,7 +126,13 @@ bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const 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; } // ============================================================================ @@ -133,6 +154,7 @@ bool SketchSolver_Group::changeConstraint( return false; BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + myStorage->blockEvents(true); bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end(); if (isNewConstraint) { @@ -144,9 +166,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(); @@ -171,28 +196,33 @@ bool SketchSolver_Group::changeConstraint( return true; } - -void SketchSolver_Group::updateConstraints() +// Update constraints if they contain specific feature +static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature) { - std::set 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(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::iterator aSCIter = aPostponed.begin(); - for (; aSCIter != aPostponed.end(); ++aSCIter) - (*aSCIter)->update(); - - myChangedConstraints.clear(); +// 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) @@ -200,8 +230,20 @@ bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) if (!checkFeatureValidity(theFeature)) return false; + bool isBlocked = myStorage->isEventsBlocked(); + if (!isBlocked) + myStorage->blockEvents(true); + myStorage->refresh(true); - return myStorage->update(theFeature); + bool isUpdated = myStorage->update(theFeature); + + updateMultiConstraints(myConstraints, theFeature); + + // events were not blocked before, the feature has not been updated, + // so it is necessary to revert blocking + if (!isUpdated && !isBlocked) + myStorage->blockEvents(false); + return isUpdated; } void SketchSolver_Group::moveFeature(FeaturePtr theFeature) @@ -209,24 +251,34 @@ void SketchSolver_Group::moveFeature(FeaturePtr theFeature) BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); // Firstly, revert changes in the fixed entities + myStorage->blockEvents(true); myStorage->refresh(true); // Secondly, search attributes of the feature in the list of the Multi constraints and update them - ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); - for (; aCIt != myConstraints.end(); ++aCIt) { - if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION || - aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION) - && aCIt->second->isUsed(theFeature)) - std::dynamic_pointer_cast(aCIt->second)->update(true); - } + updateMultiConstraints(myConstraints, theFeature); - // Then, create temporary rigid constraint + // Then, create temporary Fixed constraint SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature); if (!aConstraint) return; aConstraint->process(myStorage, getId(), getWorkplaneId()); if (aConstraint->error().empty()) setTemporary(aConstraint); + + // 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(); + } + } } // ============================================================================ @@ -274,40 +326,37 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ bool SketchSolver_Group::resolveConstraints() { - if (!myChangedConstraints.empty()) - updateConstraints(); - bool aResolved = false; - bool isGroupEmpty = isEmpty(); - if (myStorage->isNeedToResolve() && !isGroupEmpty) { + bool isGroupEmpty = isEmpty() && myStorage->isEmpty(); + if (myStorage->isNeedToResolve() && + (!isGroupEmpty || !myConflictingConstraints.empty() || myPrevResult == STATUS_FAILED)) { if (!mySketchSolver) mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver(); mySketchSolver->setGroup(myID); mySketchSolver->calculateFailedConstraints(false); myStorage->initializeSolver(mySketchSolver); + mySketchSolver->prepare(); SketchSolver_SolveStatus aResult = STATUS_OK; 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; - size_t aNbTemp = myStorage->nbTemporary(); while (true) { aResult = mySketchSolver->solve(); if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance) break; - if (aNbTemp == 0) { - // try to update parameters and resolve once again - ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin(); - for (; aConstrIt != myConstraints.end(); ++aConstrIt) - aConstrIt->second->update(); - isLastChance = true; - } else - aNbTemp = myStorage->removeTemporary(); +//// // try to update parameters and resolve once again +//// ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin(); +//// for (; aConstrIt != myConstraints.end(); ++aConstrIt) +//// aConstrIt->second->update(); + isLastChance = true; + + removeTemporaryConstraints(); mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it myStorage->initializeSolver(mySketchSolver); } @@ -315,28 +364,48 @@ bool SketchSolver_Group::resolveConstraints() } 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(""); + std::set aConflicting = myConflictingConstraints; + myConflictingConstraints.clear(); + myPrevResult = STATUS_OK; // the error message should be changed before sending the message - sendMessage(EVENT_SOLVER_REPAIRED); - myPrevSolved = true; + sendMessage(EVENT_SOLVER_REPAIRED, aConflicting); } - } else if (!myConstraints.empty()) { -// Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); - getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS()); - if (myPrevSolved) { + } else { + mySketchSolver->undo(); + if (!myConstraints.empty()) { // the error message should be changed before sending the message - sendMessage(EVENT_SOLVER_FAILED); - myPrevSolved = false; + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS()); + if (myPrevResult != aResult || myPrevResult == STATUS_UNKNOWN) { + // Obtain list of conflicting constraints + std::set aConflicting = myStorage->getConflictingConstraints(mySketchSolver); + + if (myConflictingConstraints.empty()) + sendMessage(EVENT_SOLVER_FAILED, aConflicting); + else { + std::set::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; + } } } @@ -353,6 +422,7 @@ bool SketchSolver_Group::resolveConstraints() myStorage->refresh(); } removeTemporaryConstraints(); + myStorage->blockEvents(false); myStorage->setNeedToResolve(false); return aResolved; } @@ -417,27 +487,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); } @@ -497,10 +579,6 @@ void SketchSolver_Group::removeTemporaryConstraints() for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) (*aTmpIt)->remove(); - size_t aNbTemp = myStorage->nbTemporary(); - if (aNbTemp > 0) - myStorage->removeTemporary(aNbTemp); - if (!myTempConstraints.empty()) myStorage->verifyFixed(); myStorage->setNeedToResolve(false); @@ -514,52 +592,16 @@ void SketchSolver_Group::removeTemporaryConstraints() // ============================================================================ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) { - bool isFullyRemoved = true; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for (; aCIter != myConstraints.end(); aCIter++) if (aCIter->first == theConstraint) { - if (!aCIter->second->remove()) // the constraint is not fully removed - isFullyRemoved = false; + aCIter->second->remove(); // the constraint is not fully removed + if (aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) + notifyCoincidenceChanged(aCIter->second); break; } - if (aCIter == myConstraints.end()) - return; - - if (isFullyRemoved) + if (aCIter != myConstraints.end()) myConstraints.erase(aCIter); - else if (aCIter != myConstraints.end() && - aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - // Update multicoincidence - std::list aMultiCoinc; - SolverConstraintPtr aCoincidence = aCIter->second; - while (aCIter != myConstraints.end()) { - if (aCIter->second != aCoincidence) { - ++aCIter; - continue; - } - if (aCIter->first != theConstraint) - aMultiCoinc.push_back(aCIter->first); - aCIter->second->remove(); - ConstraintConstraintMap::iterator aRemoveIt = aCIter++; - myConstraints.erase(aRemoveIt); - } - - std::list::iterator anIt = aMultiCoinc.begin(); - for (; anIt != aMultiCoinc.end(); ++anIt) - changeConstraint(*anIt); - } -} - -// ============================================================================ -// 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(); } // ============================================================================ @@ -569,7 +611,6 @@ bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint) // ============================================================================ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) { - theConstraint->makeTemporary(); myTempConstraints.insert(theConstraint); } @@ -670,3 +711,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); +}