X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=5a9652fe6955ae404f23f248f5d8da9605bf81c3;hb=8da5ddb2feeb29c481a51530a435be524bf720e9;hp=589b6a320385e25749b23f36cc8a0eed6f8110f9;hpb=5a3b32ce1c1c302bce9a4372cb6eee1965da3e09;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 589b6a320..5a9652fe6 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -28,13 +29,20 @@ #include #include +#include #include +#include #include -#include +#include #include +#include #include +#include +#include +#include #include #include +#include #include #include #include @@ -68,7 +76,7 @@ private: static Slvs_hGroup myGroupIndex; ///< index of the group }; -Slvs_hGroup GroupIndexer::myGroupIndex = 0; +Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP; static void sendMessage(const char* theMessageName) @@ -130,6 +138,15 @@ bool SketchSolver_Group::isInteract( return myFeatureStorage->isInteract(std::dynamic_pointer_cast(theFeature)); } +// check the entity is really exists +static void checkEntity(StoragePtr theStorage, Slvs_hEntity& theEntity) +{ + if (theEntity == SLVS_E_UNKNOWN) + return; + Slvs_Entity anEnt = theStorage->getEntity(theEntity); + theEntity = anEnt.h; +} + // ============================================================================ // Function: getFeatureId // Class: SketchSolver_Group @@ -140,19 +157,21 @@ Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const Slvs_hEntity aResult = SLVS_E_UNKNOWN; if (!myFeatureStorage) return aResult; - std::set aConstraints = myFeatureStorage->getConstraints(theFeature); - if (aConstraints.empty()) - return aResult; - std::set::iterator aConstrIter = aConstraints.begin(); - for (; aConstrIter != aConstraints.end(); aConstrIter++) { - ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstrIter); - if (aCIter == myConstraints.end()) - continue; + // Obtain regular constraints interacting with the feature and find its ID + ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); ++aCIter) { aResult = aCIter->second->getId(theFeature); + checkEntity(myStorage, aResult); 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); + checkEntity(myStorage, aResult); + } + return aResult; } // ============================================================================ @@ -165,19 +184,28 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const Slvs_hEntity aResult = SLVS_E_UNKNOWN; if (!myFeatureStorage) return aResult; - 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); - if (aCIter == myConstraints.end()) - continue; + // Obtain regular constraints interacting with the attribute and find its ID + ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); ++aCIter) { aResult = aCIter->second->getId(theAttribute); + checkEntity(myStorage, aResult); 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); + checkEntity(myStorage, aResult); + } + // 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); + checkEntity(myStorage, aResult); + } + return aResult; } // ============================================================================ @@ -192,7 +220,7 @@ bool SketchSolver_Group::changeConstraint( if (myWorkplaneID == SLVS_E_UNKNOWN) return false; - if (!theConstraint) + if (!theConstraint || !theConstraint->data()) return false; if (!checkFeatureValidity(theConstraint)) @@ -215,8 +243,9 @@ bool SketchSolver_Group::changeConstraint( // Additional verification of coincidence of several points if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + bool hasMultiCoincidence = false; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) { + for (; aCIter != myConstraints.end(); ++aCIter) { std::shared_ptr aCoincidence = std::dynamic_pointer_cast(aCIter->second); if (!aCoincidence) @@ -231,8 +260,12 @@ bool SketchSolver_Group::changeConstraint( if (anIt->second == aCIter->second) anIt->second = aCoinc2; aCIter->second = aCoinc2; + hasMultiCoincidence = true; } } + + if (hasMultiCoincidence) + notifyMultiConstraints(); } myConstraints[theConstraint] = aConstraint; } @@ -281,10 +314,70 @@ 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) + continue; + + std::shared_ptr aPoint; + if (aRefAttr->isObject()) { + FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object()); + if (aFeat->getKind() != SketchPlugin_Point::ID()) + continue; + aPoint = std::dynamic_pointer_cast( + aFeat->attribute(SketchPlugin_Point::COORD_ID())); + } else + aPoint = std::dynamic_pointer_cast(aRefAttr->attr()); + + if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty())) + continue; + + std::map::iterator aFound = + myParametricConstraints.find(aPoint); + if (aFound == myParametricConstraints.end()) { + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createParametricConstraint(aPoint); + if (!aConstraint) + continue; + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + myParametricConstraints[aPoint] = 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)) @@ -295,7 +388,6 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr the if (aConstraints.empty()) return false; std::set::iterator aCIter = aConstraints.begin(); - std::set aPostponed; // postponed constraints Multi-Rotation and Multi-Translation for (; aCIter != aConstraints.end(); aCIter++) { ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter); if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() || @@ -303,20 +395,33 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr the continue; myFeatureStorage->changeFeature(theFeature, aSolConIter->first); - if (aSolConIter->first->getKind() == SketchPlugin_MultiRotation::ID() || - aSolConIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) { - aPostponed.insert(aSolConIter->second); - continue; - } aSolConIter->second->addFeature(theFeature); - aSolConIter->second->update(); + myChangedConstraints.insert(aSolConIter->first); } - // Update postponed constraints - std::set::iterator aSCIter = aPostponed.begin(); - for (; aSCIter != aPostponed.end(); ++aSCIter) { - (*aSCIter)->addFeature(theFeature); - (*aSCIter)->update(); + // 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; } @@ -411,13 +516,13 @@ bool SketchSolver_Group::updateWorkplane() std::vector::iterator aParIter = aParams.begin(); for (; aParIter != aParams.end(); aParIter++) { aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage - aParIter->group = myID; + aParIter->group = SLVS_G_OUTOFGROUP; aParIter->h = myStorage->addParameter(*aParIter); } std::vector::iterator anEntIter = anEntities.begin(); for (; anEntIter != anEntities.end(); anEntIter++) { anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage - anEntIter->group = myID; + anEntIter->group = SLVS_G_OUTOFGROUP; anEntIter->wrkpl = myWorkplaneID; for (int i = 0; i < 4; i++) if (anEntIter->param[i] != SLVS_E_UNKNOWN) @@ -454,9 +559,13 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ bool SketchSolver_Group::resolveConstraints() { + if (!myChangedConstraints.empty()) + updateConstraints(); + bool aResolved = false; if (myStorage->isNeedToResolve() && !isEmpty()) { myConstrSolver.setGroupID(myID); + myConstrSolver.calculateFailedConstraints(false); myStorage->initializeSolver(myConstrSolver); int aResult = SLVS_RESULT_OKAY; @@ -480,36 +589,45 @@ bool SketchSolver_Group::resolveConstraints() isLastChance = true; } else aNbTemp = myStorage->deleteTemporaryConstraint(); + myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it myStorage->initializeSolver(myConstrSolver); } } } catch (...) { // 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; } - getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH()); 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); 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; } - getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); } 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; } - getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS()); } aResolved = true; @@ -532,18 +650,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); + } } // ============================================================================ @@ -571,9 +690,9 @@ void SketchSolver_Group::splitGroup(std::vector& theCuts) std::vector::iterator aUnuseIt = anUnusedConstraints.begin(); while (aUnuseIt != anUnusedConstraints.end()) { if (aNewFeatStorage->isInteract(*aUnuseIt)) { - size_t aShift = aUnuseIt - anUnusedConstraints.begin(); + aNewFeatStorage->changeConstraint(*aUnuseIt); anUnusedConstraints.erase(aUnuseIt); - aUnuseIt = anUnusedConstraints.begin() + aShift; + aUnuseIt = anUnusedConstraints.begin(); continue; } aUnuseIt++; @@ -597,6 +716,9 @@ void SketchSolver_Group::splitGroup(std::vector& theCuts) theCuts.push_back(aGroup); } } + + // Update feature storage + myFeatureStorage = aNewFeatStorage; } // ============================================================================ @@ -633,7 +755,11 @@ bool SketchSolver_Group::isConsistent() // ============================================================================ void SketchSolver_Group::removeTemporaryConstraints() { + std::set::iterator aTmpIt = myTempConstraints.begin(); + for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) + (*aTmpIt)->remove(); myTempConstraints.clear(); + while (myStorage->numberTemporary()) myStorage->deleteTemporaryConstraint(); // Clean lists of removed entities in the storage @@ -663,6 +789,9 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) if (aCIter == myConstraints.end()) return; + // Remove entities not used by constraints + myStorage->removeUnusedEntities(); + if (isFullyRemoved) myConstraints.erase(aCIter); else if (aCIter != myConstraints.end() && @@ -685,6 +814,8 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) std::list::iterator anIt = aMultiCoinc.begin(); for (; anIt != aMultiCoinc.end(); ++anIt) changeConstraint(*anIt); + + notifyMultiConstraints(); } } @@ -727,3 +858,102 @@ bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature) return aFactory->validate(theFeature); } +// ============================================================================ +// Function: notifyMultiConstraints +// Class: SketchSolver_Group +// Purpose: Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears +// ============================================================================ +void SketchSolver_Group::notifyMultiConstraints() +{ + ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); ++aCIter) { + if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() || + aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) { + std::shared_ptr aMulti = + std::dynamic_pointer_cast(aCIter->second); + aMulti->checkCoincidence(); + } + } +} + + + + +// =========== 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; +} +