X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=35f90dc7464da1d81e8f74aa9d4a26a4113556e8;hb=66fd2a834f8c9bf1fdfd253addd143862325f1f0;hp=419cc3e87b51241c5d45d1db49fd0020d4c70aac;hpb=5751da6b145cb9ea48f79c634c4a891e7969a865;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 419cc3e87..35f90dc74 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -20,19 +20,32 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include +#include +#include #include -#include +#include #include -#include +#include #include +#include +#include +#include #include #include +#include #include +#include +#include +#include #include #include @@ -65,6 +78,14 @@ private: Slvs_hGroup GroupIndexer::myGroupIndex = 0; +static void sendMessage(const char* theMessageName) +{ + std::shared_ptr aMessage = std::shared_ptr( + new Events_Message(Events_Loop::eventByName(theMessageName))); + Events_Loop::loop()->send(aMessage); +} + + // ======================================================== // ========= SketchSolver_Group =============== @@ -72,7 +93,8 @@ Slvs_hGroup GroupIndexer::myGroupIndex = 0; SketchSolver_Group::SketchSolver_Group( std::shared_ptr theWorkplane) - : myID(GroupIndexer::NEW_GROUP()) + : myID(GroupIndexer::NEW_GROUP()), + myPrevSolved(true) { // Initialize workplane myWorkplaneID = SLVS_E_UNKNOWN; @@ -125,11 +147,12 @@ Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const Slvs_hEntity aResult = SLVS_E_UNKNOWN; if (!myFeatureStorage) return aResult; + // Obtain regular constraints interacting with the feature and find its ID std::set aConstraints = myFeatureStorage->getConstraints(theFeature); if (aConstraints.empty()) return aResult; std::set::iterator aConstrIter = aConstraints.begin(); - for (; aConstrIter != aConstraints.end(); aConstrIter++) { + for (; aConstrIter != aConstraints.end(); ++aConstrIter) { ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter); if (aCIter == myConstraints.end()) continue; @@ -137,7 +160,11 @@ Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const if (aResult != SLVS_E_UNKNOWN) return aResult; } - return SLVS_E_UNKNOWN; + // The feature is not found, check it in the temporary constraints + std::set::iterator aTmpCIter = myTempConstraints.begin(); + for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) + aResult = (*aTmpCIter)->getId(theFeature); + return aResult; } // ============================================================================ @@ -150,9 +177,8 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const Slvs_hEntity aResult = SLVS_E_UNKNOWN; if (!myFeatureStorage) return aResult; + // Obtain regular constraints interacting with the attribute and find its ID std::set aConstraints = myFeatureStorage->getConstraints(theAttribute); - if (aConstraints.empty()) - return aResult; std::set::iterator aConstrIter = aConstraints.begin(); for (; aConstrIter != aConstraints.end(); aConstrIter++) { ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter); @@ -162,7 +188,16 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const if (aResult != SLVS_E_UNKNOWN) return aResult; } - return SLVS_E_UNKNOWN; + // The attribute is not found, check it in the temporary constraints + std::set::const_iterator aTmpCIter = myTempConstraints.begin(); + for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) + aResult = (*aTmpCIter)->getId(theAttribute); + // Last chance to find attribute in parametric constraints + std::map::const_iterator aParIter = + myParametricConstraints.find(theAttribute); + if (aParIter != myParametricConstraints.end()) + aResult = aParIter->second->getId(theAttribute); + return aResult; } // ============================================================================ @@ -177,7 +212,10 @@ bool SketchSolver_Group::changeConstraint( if (myWorkplaneID == SLVS_E_UNKNOWN) return false; - if (!theConstraint) + if (!theConstraint || !theConstraint->data()) + return false; + + if (!checkFeatureValidity(theConstraint)) return false; bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end(); @@ -206,8 +244,13 @@ bool SketchSolver_Group::changeConstraint( std::shared_ptr aCoinc2 = std::dynamic_pointer_cast(aConstraint); if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) { - aCoincidence->attach(aCoinc2); - aConstraint = aCoincidence; + aCoinc2->attach(aCoincidence); + // update other coincidences + ConstraintConstraintMap::iterator anIt = aCIter; + for (++anIt; anIt != myConstraints.end(); ++anIt) + if (anIt->second == aCIter->second) + anIt->second = aCoinc2; + aCIter->second = aCoinc2; } } } @@ -242,12 +285,14 @@ bool SketchSolver_Group::changeConstraint( theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A())); if (aRefAttr && aRefAttr->isObject()) { FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); - if (aConstraint) { - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - setTemporary(aConstraint); + if (aFeature) { + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); + if (aConstraint) { + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + setTemporary(aConstraint); + } } } } @@ -256,12 +301,66 @@ bool SketchSolver_Group::changeConstraint( myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); myFeatureStorage->changeConstraint(theConstraint); + // Check the attributes of constraint are given by parametric expression + std::list anAttributes = + theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); + std::list::iterator anAttrIt = anAttributes.begin(); + for (; anAttrIt != anAttributes.end(); ++anAttrIt) { + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(*anAttrIt); + if (!aRefAttr || aRefAttr->isObject()) + continue; + std::shared_ptr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty())) + continue; + + std::map::iterator aFound = + myParametricConstraints.find(aRefAttr->attr()); + if (aFound == myParametricConstraints.end()) { + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createParametricConstraint(aRefAttr->attr()); + if (!aConstraint) + continue; + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + myParametricConstraints[aRefAttr->attr()] = aConstraint; + } else + aFound->second->update(); + } + return true; } +void SketchSolver_Group::updateConstraints() +{ + 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(); + } + + // Update postponed constraints + std::set::iterator aSCIter = aPostponed.begin(); + for (; aSCIter != aPostponed.end(); ++aSCIter) + (*aSCIter)->update(); + + myChangedConstraints.clear(); +} + bool SketchSolver_Group::updateFeature(std::shared_ptr theFeature) { + if (!checkFeatureValidity(theFeature)) + return false; + std::set aConstraints = myFeatureStorage->getConstraints(std::dynamic_pointer_cast(theFeature)); if (aConstraints.empty()) @@ -273,8 +372,34 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr the !aSolConIter->first->data()->isValid()) continue; myFeatureStorage->changeFeature(theFeature, aSolConIter->first); + aSolConIter->second->addFeature(theFeature); - aSolConIter->second->update(); + myChangedConstraints.insert(aSolConIter->first); + } + + // Search attributes of the feature in the set of parametric constraints and update them + std::list anAttrList = + theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::iterator anAttrIt = anAttrList.begin(); + for (; anAttrIt != anAttrList.end(); ++anAttrIt) { + std::map::iterator aFound = + myParametricConstraints.find(*anAttrIt); + if (aFound != myParametricConstraints.end()) + aFound->second->update(); + else { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(*anAttrIt); + if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) { + // Create new parametric constraint + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt); + if (!aConstraint) + continue; + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + myParametricConstraints[*anAttrIt] = aConstraint; + } + } } return true; } @@ -283,7 +408,7 @@ void SketchSolver_Group::moveFeature(std::shared_ptr theFe { // Firstly, create temporary rigid constraint SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature); + SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature); if (!aConstraint) return; aConstraint->setGroup(this); @@ -412,6 +537,9 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ bool SketchSolver_Group::resolveConstraints() { + if (!myChangedConstraints.empty()) + updateConstraints(); + bool aResolved = false; if (myStorage->isNeedToResolve() && !isEmpty()) { myConstrSolver.setGroupID(myID); @@ -424,27 +552,59 @@ bool SketchSolver_Group::resolveConstraints() else { // To avoid overconstraint situation, we will remove temporary constraints one-by-one // and try to find the case without overconstraint - int aNbTemp = (int)myTempConstraints.size(); + bool isLastChance = false; + int aNbTemp = myStorage->numberTemporary(); while (true) { aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY || aNbTemp <= 0) + if (aResult == SLVS_RESULT_OKAY || isLastChance) break; - aNbTemp = myStorage->deleteTemporaryConstraint(); + 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->deleteTemporaryConstraint(); myStorage->initializeSolver(myConstrSolver); } } } catch (...) { - Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this); +// Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this); + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH()); + if (myPrevSolved) { + // the error message should be changed before sending the message + sendMessage(EVENT_SOLVER_FAILED); + myPrevSolved = false; + } return false; } if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes myFeatureStorage->blockEvents(true); + // First refresh parametric constraints to satisfy parameters + std::map::iterator aParIter = myParametricConstraints.begin(); + for (; aParIter != myParametricConstraints.end(); ++aParIter) + aParIter->second->refresh(); + // Update all other constraints ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) + for (; aConstrIter != myConstraints.end(); ++aConstrIter) aConstrIter->second->refresh(); myFeatureStorage->blockEvents(false); - } else if (!myConstraints.empty()) - Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); + if (!myPrevSolved) { + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); + // the error message should be changed before sending the message + sendMessage(EVENT_SOLVER_REPAIRED); + myPrevSolved = true; + } + } else if (!myConstraints.empty()) { +// Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); + 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; + } + } aResolved = true; } @@ -466,18 +626,19 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) if (!myFeatureStorage) myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); - std::vector aComplexConstraints; + std::set aConstraints; ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin(); - // append simple constraints for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++) - if (isComplexConstraint(aConstrIter->first)) - aComplexConstraints.push_back(aConstrIter->first); - else - changeConstraint(aConstrIter->first); - // append complex constraints - std::vector::iterator aComplexIter = aComplexConstraints.begin(); - for (; aComplexIter != aComplexConstraints.end(); aComplexIter++) - changeConstraint(*aComplexIter); + aConstraints.insert(aConstrIter->first); + + std::list aSortedConstraints = selectApplicableFeatures(aConstraints); + std::list::iterator aSCIter = aSortedConstraints.begin(); + for (; aSCIter != aSortedConstraints.end(); ++aSCIter) { + ConstraintPtr aConstr = std::dynamic_pointer_cast(*aSCIter); + if (!aConstr) + continue; + changeConstraint(aConstr); + } } // ============================================================================ @@ -546,22 +707,15 @@ bool SketchSolver_Group::isConsistent() bool aResult = myFeatureStorage->isConsistent(); if (!aResult) { // remove invalid entities + std::set anInvalidConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - while (aCIter != myConstraints.end()) { - std::list aConstraints = aCIter->second->constraints(); - std::list::iterator anIt = aConstraints.begin(); - for (; anIt != aConstraints.end(); anIt++) - if (!(*anIt)->data() || !(*anIt)->data()->isValid()) - if (aCIter->second->remove(*anIt)) { - // the constraint is fully removed, detach it from the list - ConstraintConstraintMap::iterator aTmpIt = aCIter++; - myFeatureStorage->removeConstraint(aTmpIt->first); - myConstraints.erase(aTmpIt); - break; - } - if (anIt == aConstraints.end()) - aCIter++; + for (; aCIter != myConstraints.end(); ++aCIter) { + if (!aCIter->first->data() || !aCIter->first->data()->isValid()) + anInvalidConstraints.insert(aCIter->first); } + std::set::const_iterator aRemoveIt = anInvalidConstraints.begin(); + for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt) + removeConstraint(*aRemoveIt); } return aResult; } @@ -574,8 +728,13 @@ bool SketchSolver_Group::isConsistent() // ============================================================================ void SketchSolver_Group::removeTemporaryConstraints() { + std::set::iterator aTmpIt = myTempConstraints.begin(); + for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) + (*aTmpIt)->remove(); myTempConstraints.clear(); - myStorage->removeTemporaryConstraints(); + + while (myStorage->numberTemporary()) + myStorage->deleteTemporaryConstraint(); // Clean lists of removed entities in the storage std::set aRemPar; std::set aRemEnt; @@ -591,16 +750,41 @@ void SketchSolver_Group::removeTemporaryConstraints() // ============================================================================ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) { + bool isFullyRemoved = true; myFeatureStorage->removeConstraint(theConstraint); ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for (; aCIter != myConstraints.end(); aCIter++) if (aCIter->second->hasConstraint(theConstraint)) { if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed - aCIter = myConstraints.end(); + isFullyRemoved = false; break; } - if (aCIter != myConstraints.end()) + if (aCIter == myConstraints.end()) + return; + + if (isFullyRemoved) 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(aCIter->first); + ConstraintConstraintMap::iterator aRemoveIt = aCIter++; + myConstraints.erase(aRemoveIt); + } + + std::list::iterator anIt = aMultiCoinc.begin(); + for (; anIt != aMultiCoinc.end(); ++anIt) + changeConstraint(*anIt); + } } // ============================================================================ @@ -626,3 +810,101 @@ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) myTempConstraints.insert(theConstraint); } + +// ============================================================================ +// Function: checkFeatureValidity +// Class: SketchSolver_Group +// Purpose: verifies is the feature valid +// ============================================================================ +bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature) +{ + if (!theFeature || !theFeature->data()->isValid()) + return true; + + SessionPtr aMgr = ModelAPI_Session::get(); + ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); + return aFactory->validate(theFeature); +} + + + + + +// =========== Auxiliary functions ======================================== +static double featureToVal(FeaturePtr theFeature) +{ + if (theFeature->getKind() == SketchPlugin_Sketch::ID()) + return 0.0; // sketch + ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); + if (!aConstraint) + return 1.0; // features (arc, circle, line, point) + + const std::string& anID = aConstraint->getKind(); + if (anID == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrA = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + 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 + return 2.5; + } + if (anID == SketchPlugin_ConstraintDistance::ID() || + anID == SketchPlugin_ConstraintLength::ID() || + anID == SketchPlugin_ConstraintRadius::ID()) + return 3.0; + if (anID == SketchPlugin_ConstraintAngle::ID()) + return 3.5; + if (anID == SketchPlugin_ConstraintHorizontal::ID() || + anID == SketchPlugin_ConstraintVertical::ID() || + anID == SketchPlugin_ConstraintParallel::ID() || + anID == SketchPlugin_ConstraintPerpendicular::ID()) + return 4.0; + if (anID == SketchPlugin_ConstraintEqual::ID()) + return 5.0; + if (anID == SketchPlugin_ConstraintTangent::ID() || + anID == SketchPlugin_ConstraintMirror::ID()) + return 6.0; + if (anID == SketchPlugin_ConstraintRigid::ID()) + return 7.0; + if (anID == SketchPlugin_MultiRotation::ID() || + anID == SketchPlugin_MultiTranslation::ID()) + return 8.0; + + // all other constraints are placed between Equal and Tangent constraints + return 5.5; +} + +static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2) +{ + return featureToVal(theFeature1) < featureToVal(theFeature2); +} + +std::list SketchSolver_Group::selectApplicableFeatures(const std::set& theObjects) +{ + std::list aResult; + std::list::iterator aResIt; + + 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. + FeaturePtr aFeature = std::dynamic_pointer_cast(*anObjIter); + if (!aFeature) + continue; + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(aFeature); + if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) || + aFeature->getKind() == SketchPlugin_ConstraintFillet::ID()) + continue; + + // Find the place where to insert a feature + for (aResIt = aResult.begin(); aResIt != aResult.end(); ++aResIt) + if (isLess(aFeature, *aResIt)) + break; + aResult.insert(aResIt, aFeature); + } + + return aResult; +} +