X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Group.cpp;h=f437103ac38527035421f86396b2fe5c6c0d26fd;hb=87b6a30a3afb8fb32e7e43ade8d9c947d9eb1684;hp=e630978ecc48952bde87291222a7b16f1104b44a;hpb=653805f5d615b18e3a5a9640a86ae55ba5779d69;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index e630978ec..f437103ac 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -1,68 +1,71 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Group.cpp -// Created: 27 May 2014 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// #include "SketchSolver_Group.h" - -#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 - -#include -#include -#include -#include -#include +#include +#include -#include -#include +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); +} -/// \brief This class is used to give unique index to the groups -class GroupIndexer +static void sendMessage(const char* theMessageName, const std::set& theConflicting) { -public: - /// \brief Return vacant index - static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; } - /// \brief Removes the index - static void REMOVE_GROUP(const Slvs_hGroup& theIndex) { - if (myGroupIndex == theIndex) - myGroupIndex--; - } + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName))); + aMessage->setObjects(theConflicting); + Events_Loop::loop()->send(aMessage); +} -private: - GroupIndexer() {}; +static void sendMessage(const char* theMessageName, + const CompositeFeaturePtr& theSketch, + const int theDOF) +{ + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName))); - static Slvs_hGroup myGroupIndex; ///< index of the group -}; + std::set anObjects; + anObjects.insert(theSketch); + aMessage->setObjects(anObjects); + aMessage->dof(theDOF); -Slvs_hGroup GroupIndexer::myGroupIndex = 0; + Events_Loop::loop()->send(aMessage); +} @@ -70,99 +73,25 @@ Slvs_hGroup GroupIndexer::myGroupIndex = 0; // ========= SketchSolver_Group =============== // ======================================================== -SketchSolver_Group::SketchSolver_Group( - std::shared_ptr theWorkplane) - : myID(GroupIndexer::NEW_GROUP()) +SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane) + : mySketch(theWorkplane), + myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN), + myDOF(0), + myIsEventsBlocked(false), + myMultiConstraintUpdateStack(0) { - // Initialize workplane - myWorkplaneID = SLVS_E_UNKNOWN; -#ifndef NDEBUG - assert(addWorkplane(theWorkplane)); -#else - addWorkplane(theWorkplane); -#endif + mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver); + myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver)); } SketchSolver_Group::~SketchSolver_Group() { myConstraints.clear(); - GroupIndexer::REMOVE_GROUP(myID); -} - -// ============================================================================ -// Function: isBaseWorkplane -// Class: SketchSolver_Group -// Purpose: verify the group is based on the given workplane -// ============================================================================ -bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const -{ - return theWorkplane == mySketch; -} - -// ============================================================================ -// Function: isInteract -// Class: SketchSolver_Group -// Purpose: verify are there any entities in the group used by given constraint -// ============================================================================ -bool SketchSolver_Group::isInteract( - std::shared_ptr theFeature) const -{ - // Empty group interacts with everything - if (isEmpty()) return true; - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (aConstraint) - return myFeatureStorage->isInteract(aConstraint); - return myFeatureStorage->isInteract(std::dynamic_pointer_cast(theFeature)); -} - -// ============================================================================ -// Function: getFeatureId -// Class: SketchSolver_Group -// Purpose: Find the identifier of the feature, if it already exists in the group -// ============================================================================ -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; - aResult = aCIter->second->getId(theFeature); - if (aResult != SLVS_E_UNKNOWN) - return aResult; + // send the message that there is no more conflicting constraints + if (!myConflictingConstraints.empty()) { + sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints); + myConflictingConstraints.clear(); } - return SLVS_E_UNKNOWN; -} - -// ============================================================================ -// Function: getAttributeId -// Class: SketchSolver_Group -// Purpose: Find the identifier of the attribute, if it already exists in the group -// ============================================================================ -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; - aResult = aCIter->second->getId(theAttribute); - if (aResult != SLVS_E_UNKNOWN) - return aResult; - } - return SLVS_E_UNKNOWN; } // ============================================================================ @@ -173,228 +102,62 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const bool SketchSolver_Group::changeConstraint( std::shared_ptr theConstraint) { - // There is no workplane yet, something wrong - if (myWorkplaneID == SLVS_E_UNKNOWN) - return false; - - if (!theConstraint) - return false; - bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end(); if (isNewConstraint) { // Add constraint to the current group - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createConstraint(theConstraint); + SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createConstraint(theConstraint); if (!aConstraint) return false; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); + aConstraint->process(myStorage, myIsEventsBlocked); 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); - } - - // Additional verification of coincidence of several points - if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) { - std::shared_ptr aCoincidence = - std::dynamic_pointer_cast(aCIter->second); - if (!aCoincidence) - continue; - std::shared_ptr aCoinc2 = - std::dynamic_pointer_cast(aConstraint); - if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) { - aCoincidence->attach(aCoinc2); - aConstraint = aCoincidence; - } - } + Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send(); } myConstraints[theConstraint] = aConstraint; } else myConstraints[theConstraint]->update(); - // Fix base features for fillet - if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) { - std::list anAttrList = - theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anAttrIter = anAttrList.begin(); - for (; anAttrIter != anAttrList.end(); anAttrIter++) { - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(*anAttrIter); - if (!aRefAttr || !aRefAttr->isObject()) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - setTemporary(aConstraint); - } - } - //// Fix base features for mirror - //if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { - // AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - // theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_B())); - // fixFeaturesList(aRefList); - //} - - if (!myFeatureStorage) - myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); - myFeatureStorage->changeConstraint(theConstraint); - - return true; -} - - -bool SketchSolver_Group::updateFeature(std::shared_ptr theFeature) -{ - std::set aConstraints = - myFeatureStorage->getConstraints(std::dynamic_pointer_cast(theFeature)); - if (aConstraints.empty()) - return false; - std::set::iterator aCIter = aConstraints.begin(); - for (; aCIter != aConstraints.end(); aCIter++) { - ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter); - if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() || - !aSolConIter->first->data()->isValid()) - continue; - myFeatureStorage->changeFeature(theFeature, aSolConIter->first); - aSolConIter->second->addFeature(theFeature); - aSolConIter->second->update(); - } + // constraint is created/updated => reset stack of "multi" constraints updates + myMultiConstraintUpdateStack = 0; return true; } -void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) +bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) { - updateFeature(theFeature); - // Temporary rigid constraint - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature); - if (!aConstraint) - return; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - if (aConstraint->error().empty()) - setTemporary(aConstraint); + return myStorage->update(theFeature); } -// ============================================================================ -// Function: fixFeaturesList -// Class: SketchSolver_Group -// Purpose: Apply temporary rigid constraints for the list of features -// ============================================================================ -void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList) +bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) { - std::list aList = theList->list(); - std::list::iterator anIt = aList.begin(); - std::list aFeatures; - // Sort features, at begining there are features used by Equal constraint - for (; anIt != aList.end(); anIt++) { - if (!(*anIt)) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); - std::set aConstraints = myFeatureStorage->getConstraints(aFeature); - std::set::iterator aCIter = aConstraints.begin(); - for (; aCIter != aConstraints.end(); aCIter++) - if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID()) - break; - if (aCIter != aConstraints.end()) - aFeatures.push_front(aFeature); - else - aFeatures.push_back(aFeature); + bool isFeatureExists = (myStorage->entity(theFeature).get() != 0); + if (myDOF == 0 && isFeatureExists) { + // avoid moving elements of fully constrained sketch + myStorage->refresh(); + return true; } - std::list::iterator aFeatIter = aFeatures.begin(); - for (; aFeatIter != aFeatures.end(); aFeatIter++) { - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); + // Create temporary Fixed constraint + std::shared_ptr aConstraint = + PlaneGCSSolver_Tools::createMovementConstraint(theFeature); + if (!aConstraint) + return false; + SolverConstraintPtr(aConstraint)->process(myStorage, myIsEventsBlocked); + if (aConstraint->error().empty()) { setTemporary(aConstraint); - } -} + if (!myStorage->isEmpty()) + myStorage->setNeedToResolve(true); -// ============================================================================ -// Function: addWorkplane -// Class: SketchSolver_Group -// Purpose: create workplane for the group -// ============================================================================ -bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) -{ - if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) - return false; // the workplane already exists or the function parameter is not Sketch + mySketchSolver->initialize(); + aConstraint->moveFeature(); + } - mySketch = theSketch; - updateWorkplane(); + // notify all observers that theFeature has been changed + myStorage->notify(theFeature); return true; } -// ============================================================================ -// Function: updateWorkplane -// Class: SketchSolver_Group -// Purpose: update parameters of workplane -// ============================================================================ -bool SketchSolver_Group::updateWorkplane() -{ - if (!myStorage) // Create storage if not exists - myStorage = StoragePtr(new SketchSolver_Storage); - SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance(); - - std::vector anEntities; - std::vector aParams; - if (!aBuilder->createWorkplane(mySketch, anEntities, aParams)) - return false; - - if (myWorkplaneID == SLVS_E_UNKNOWN) { - myWorkplaneID = anEntities.back().h; - // Add new workplane elements - 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->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->wrkpl = myWorkplaneID; - for (int i = 0; i < 4; i++) - if (anEntIter->param[i] != SLVS_E_UNKNOWN) - anEntIter->param[i] = aParams[anEntIter->param[i]-1].h; - for (int i = 0; i < 4; i++) - if (anEntIter->point[i] != SLVS_E_UNKNOWN) - anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h; - anEntIter->h = myStorage->addEntity(*anEntIter); - } - } else { - // Update existent workplane - const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID); - const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]); - const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal); - // Get parameters and update them - Slvs_hParam aWPParams[7] = { - anOrigin.param[0], anOrigin.param[1], anOrigin.param[2], - aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3] - }; - std::vector::iterator aParIter = aParams.begin(); - for (int i = 0; aParIter != aParams.end(); aParIter++, i++) { - Slvs_Param aParam = myStorage->getParameter(aWPParams[i]); - aParam.val = aParIter->val; - myStorage->updateParameter(aParam); - } - } - return myWorkplaneID > 0; -} - // ============================================================================ // Function: resolveConstraints // Class: SketchSolver_Group @@ -402,158 +165,163 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ bool SketchSolver_Group::resolveConstraints() { + static const int MAX_STACK_SIZE = 5; + // check the "Multi" constraints do not drop sketch into infinite loop + if (myMultiConstraintUpdateStack > MAX_STACK_SIZE) { + myMultiConstraintUpdateStack = 0; + myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED; + // generate error message due to loop update of the sketch + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR()) + ->setValue(SketchSolver_Error::INFINITE_LOOP()); + sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints); + return false; + } + bool aResolved = false; - if (myStorage->isNeedToResolve() && !isEmpty()) { - myConstrSolver.setGroupID(myID); - myStorage->initializeSolver(myConstrSolver); + bool isGroupEmpty = isEmpty() && myStorage->isEmpty(); + if (myStorage->isNeedToResolve() && + (!isGroupEmpty || !myConflictingConstraints.empty() || + myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED)) { - int aResult = SLVS_RESULT_OKAY; + PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK; try { - if (myStorage->hasDuplicatedConstraint()) - aResult = SLVS_RESULT_INCONSISTENT; - 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(); - while (true) { - aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY || aNbTemp <= 0) - break; - aNbTemp = myStorage->removeFirstTemporaryConstraint(); - myStorage->initializeSolver(myConstrSolver); - } + if (!isGroupEmpty) + aResult = mySketchSolver->solve(); + if (aResult == PlaneGCSSolver_Solver::STATUS_FAILED && + !myTempConstraints.empty()) { + mySketchSolver->undo(); + removeTemporaryConstraints(); + aResult = mySketchSolver->solve(); } } catch (...) { - Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this); + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR()) + ->setValue(SketchSolver_Error::SOLVESPACE_CRASH()); + if (myPrevResult == PlaneGCSSolver_Solver::STATUS_OK || + myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) { + // the error message should be changed before sending the message + sendMessage(EVENT_SOLVER_FAILED); + myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED; + } + mySketchSolver->undo(); return false; } - if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes - myFeatureStorage->blockEvents(true); - ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - aConstrIter->second->refresh(); - myFeatureStorage->blockEvents(false); - } else if (!myConstraints.empty()) - Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); - - aResolved = true; - } + // solution succeeded, store results into correspondent attributes + if (aResult == PlaneGCSSolver_Solver::STATUS_OK || + aResult == PlaneGCSSolver_Solver::STATUS_EMPTYSET) { + myStorage->setNeedToResolve(false); + myStorage->refresh(); + + // additional check that copied entities used in Mirror and other "Multi" constraints + // is not connected with their originals by constraints. + myMultiConstraintUpdateStack += 1; + aResolved = true; + if (myStorage->isNeedToResolve()) + aResolved = resolveConstraints(); + + if (aResolved) { + myMultiConstraintUpdateStack -= 1; + + if (myPrevResult != PlaneGCSSolver_Solver::STATUS_OK || + myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) { + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); + std::set aConflicting = myConflictingConstraints; + myConflictingConstraints.clear(); + myPrevResult = PlaneGCSSolver_Solver::STATUS_OK; + // the error message should be changed before sending the message + sendMessage(EVENT_SOLVER_REPAIRED, aConflicting); + } + } + + // show degrees of freedom + computeDoF(); + } 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 == PlaneGCSSolver_Solver::STATUS_UNKNOWN || + myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED) { + // Obtain list of conflicting constraints + std::set aConflicting = myStorage->getConflictingConstraints(mySketchSolver); + + if (!myConflictingConstraints.empty()) { + 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; + if (!myConflictingConstraints.empty()) + sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints); + myPrevResult = aResult; + } + } + } + + } else if (isGroupEmpty && isWorkplaneValid()) + computeDoF(); removeTemporaryConstraints(); myStorage->setNeedToResolve(false); return aResolved; } // ============================================================================ -// Function: mergeGroups +// Function: computeDoF // Class: SketchSolver_Group -// Purpose: append specified group to the current group +// Purpose: compute DoF of the sketch and set corresponding field // ============================================================================ -void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) +void SketchSolver_Group::computeDoF() { - // If specified group is empty, no need to merge - if (theGroup.isEmpty()) - return; - if (!myFeatureStorage) - myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); - - std::vector aComplexConstraints; - 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); -} - -// ============================================================================ -// Function: splitGroup -// Class: SketchSolver_Group -// Purpose: divide the group into several subgroups -// ============================================================================ -void SketchSolver_Group::splitGroup(std::vector& theCuts) -{ - // Obtain constraints, which should be separated - FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage); - std::vector anUnusedConstraints; - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for ( ; aCIter != myConstraints.end(); aCIter++) { - std::list aBaseConstraints = aCIter->second->constraints(); - std::list::iterator anIter = aBaseConstraints.begin(); - for (; anIter != aBaseConstraints.end(); anIter++) - if (aNewFeatStorage->isInteract(*anIter)) { - aNewFeatStorage->changeConstraint(*anIter); - } else - anUnusedConstraints.push_back(*anIter); - } + std::ostringstream aDoFMsg; + int aDoF = mySketchSolver->dof(); + /// "DoF = 0" content of string value is used in PartSet by Sketch edit + /// If it is changed, it should be corrected also there + if (aDoF == 0) + aDoFMsg << "Sketch is fully fixed (DoF = 0)"; + else + aDoFMsg << "DoF (degrees of freedom) = " << aDoF; + mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str()); - // Check the unused constraints once again, because they may become interacted with new storage since adding constraints - std::vector::iterator aUnuseIt = anUnusedConstraints.begin(); - while (aUnuseIt != anUnusedConstraints.end()) { - if (aNewFeatStorage->isInteract(*aUnuseIt)) { - size_t aShift = aUnuseIt - anUnusedConstraints.begin(); - anUnusedConstraints.erase(aUnuseIt); - aUnuseIt = anUnusedConstraints.begin() + aShift; - continue; - } - aUnuseIt++; - } + if (aDoF > 0 && myDOF == 0) + sendMessage(EVENT_SKETCH_UNDER_CONSTRAINED, mySketch, aDoF); + else if (aDoF == 0 && myDOF > 0) + sendMessage(EVENT_SKETCH_FULLY_CONSTRAINED, mySketch, aDoF); + else if (aDoF < 0) + sendMessage(EVENT_SKETCH_OVER_CONSTRAINED, mySketch, aDoF); - std::vector::iterator aCutsIter; - aUnuseIt = anUnusedConstraints.begin(); - for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) { - // Remove unused constraints - 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()) { - // Add new group - SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch); - aGroup->changeConstraint(*aUnuseIt); - theCuts.push_back(aGroup); - } - } + myDOF = aDoF; } // ============================================================================ -// Function: isConsistent +// Function: repairConsistency // Class: SketchSolver_Group // Purpose: search removed entities and constraints // ============================================================================ -bool SketchSolver_Group::isConsistent() +void SketchSolver_Group::repairConsistency() { - if (!myFeatureStorage) // no one constraint is initialized yet - return true; - - bool aResult = myFeatureStorage->isConsistent(); - if (!aResult) { - // remove invalid entities + if (!areConstraintsValid() || !myStorage->areFeaturesValid()) { + // remove invalid constraints + 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); + + // remove invalid features + myStorage->removeInvalidEntities(); + + // show DoF + computeDoF(); } - return aResult; } // ============================================================================ @@ -564,13 +332,16 @@ bool SketchSolver_Group::isConsistent() // ============================================================================ void SketchSolver_Group::removeTemporaryConstraints() { - myTempConstraints.clear(); - myStorage->removeTemporaryConstraints(); - // Clean lists of removed entities in the storage - std::set aRemPar; - std::set aRemEnt; - std::set aRemCon; - myStorage->getRemoved(aRemPar, aRemEnt, aRemCon); + if (!myTempConstraints.empty()) { + mySketchSolver->removeConstraint(CID_MOVEMENT); + + std::set::iterator aTmpIt = myTempConstraints.begin(); + for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) + (*aTmpIt)->remove(); + + myTempConstraints.clear(); + } + myStorage->setNeedToResolve(false); } @@ -581,12 +352,13 @@ void SketchSolver_Group::removeTemporaryConstraints() // ============================================================================ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) { - 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(); + if (aCIter->first == theConstraint) { + aCIter->second->remove(); // the constraint is not fully removed + + // constraint is removed => reset stack of "multi" constraints updates + myMultiConstraintUpdateStack = 0; break; } if (aCIter != myConstraints.end()) @@ -594,25 +366,42 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) } // ============================================================================ -// Function: isComplexConstraint +// Function: setTemporary // Class: SketchSolver_Group -// Purpose: verifies the constraint is complex, i.e. it needs another constraints to be created before +// Purpose: append given constraint to the group of temporary constraints // ============================================================================ -bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint) +void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) { - return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() || - theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() || - theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID(); + myTempConstraints.insert(theConstraint); } // ============================================================================ -// Function: setTemporary +// Function: blockEvents // Class: SketchSolver_Group -// Purpose: append given constraint to th group of temporary constraints +// Purpose: block or unblock events from features in this group // ============================================================================ -void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) +void SketchSolver_Group::blockEvents(bool isBlocked) { - theConstraint->makeTemporary(); - myTempConstraints.insert(theConstraint); + if (myIsEventsBlocked == isBlocked) + return; + + // block/unblock events from the features in the storage + myStorage->blockEvents(isBlocked); + + // block/unblock events from constraints + ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) + aCIt->second->blockEvents(isBlocked); + + myIsEventsBlocked = isBlocked; } +bool SketchSolver_Group::areConstraintsValid() const +{ + // Check the constraints are valid + ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); ++aCIter) + if (!aCIter->first->data() || !aCIter->first->data()->isValid()) + return false; + return true; +}