X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=1ee8c9e3dfc9c86fe4d24c662120e3864b451b81;hb=9fb3a575c3b7585b7789c48e8fbfa1db8619a173;hp=5b242b63264e460bb16445454c7be0bfe5fe4d10;hpb=29d446f4dd2969d80087745fe44adb5638d13de7;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 5b242b632..1ee8c9e3d 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -19,6 +19,7 @@ #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) { @@ -147,6 +169,9 @@ bool SketchSolver_Group::changeConstraint( Events_Error::send(aConstraint->error(), this); } myConstraints[theConstraint] = aConstraint; + + if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) + notifyCoincidenceChanged(myConstraints[theConstraint]); } else myConstraints[theConstraint]->update(); @@ -171,36 +196,54 @@ 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) { 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) @@ -208,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); - } - - // 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); + + // 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(); + } + } } // ============================================================================ @@ -273,11 +326,8 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ 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(); @@ -285,6 +335,7 @@ bool SketchSolver_Group::resolveConstraints() mySketchSolver->setGroup(myID); mySketchSolver->calculateFailedConstraints(false); myStorage->initializeSolver(mySketchSolver); + mySketchSolver->prepare(); SketchSolver_SolveStatus aResult = STATUS_OK; try { @@ -294,19 +345,17 @@ bool SketchSolver_Group::resolveConstraints() // 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); } @@ -314,28 +363,50 @@ 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) { + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + 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(""); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); // 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 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()); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + 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; + } } } @@ -352,6 +423,7 @@ bool SketchSolver_Group::resolveConstraints() myStorage->refresh(); } removeTemporaryConstraints(); + myStorage->blockEvents(false); myStorage->setNeedToResolve(false); return aResolved; } @@ -496,10 +568,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); @@ -513,52 +581,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(); } // ============================================================================ @@ -568,7 +600,6 @@ bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint) // ============================================================================ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) { - theConstraint->makeTemporary(); myTempConstraints.insert(theConstraint); } @@ -669,3 +700,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); +}