X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Manager.cpp;h=8bebc53c4247037984ef7b9c14fb112e7c6903f4;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=dec3ead7e8c407f5e7a1ddb982027f6cfe6a0173;hpb=908f8bf97d07537a33c06349e86ea6a6aa4d7323;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index dec3ead7e..8bebc53c4 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -1,62 +1,106 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Manager.cpp -// Created: 08 May 2014 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2024 CEA, EDF +// +// 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_Manager.h" #include "SketchSolver_Error.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 -#include -#include +/// Global constraint manager object +static SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); -static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); +/// \brief Verifies is the feature valid +static bool isFeatureValid(FeaturePtr theFeature) +{ + if (!theFeature || !theFeature->data() || !theFeature->data()->isValid()) + return false; -// Initialization of constraint manager self pointer -SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; + SessionPtr aMgr = ModelAPI_Session::get(); + ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); + return aFactory->validate(theFeature); +} + +typedef std::map> IndexedFeatureMap; + +static void featuresOrderedByCreation(const std::set& theOriginalFeatures, + IndexedFeatureMap& theOrderedFeatures) +{ + std::set::iterator aFeatIter = theOriginalFeatures.begin(); + for (; aFeatIter != theOriginalFeatures.end(); aFeatIter++) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (aFeature && !aFeature->isMacro() && aFeature->data() && aFeature->data()->isValid()) { + theOrderedFeatures[aFeature->data()->featureId()] = aFeature; + } + } +} + +static void featuresOrderedByType(const std::set& theOriginalFeatures, + IndexedFeatureMap& theOrderedFeatures, + CompositeFeaturePtr& theSketch) +{ + int aFeatureIndex = 0; + int aConstraintIndex = (int)theOriginalFeatures.size(); + + std::set::iterator aFeatIter = theOriginalFeatures.begin(); + for (; aFeatIter != theOriginalFeatures.end(); aFeatIter++) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (aFeature) { + if (!aFeature->isMacro() && aFeature->data() && aFeature->data()->isValid()) { + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(aFeature); + if (aConstraint) + theOrderedFeatures[++aConstraintIndex] = aFeature; + else + theOrderedFeatures[++aFeatureIndex] = aFeature; + } + } + else { + CompositeFeaturePtr aSketch = + std::dynamic_pointer_cast(*aFeatIter); + if (aSketch && aSketch->getKind() == SketchPlugin_Sketch::ID()) + theSketch = aSketch; + } + } +} + +static void setPoint(AttributePtr theAttribute, + const int thePointIndex, + const std::shared_ptr theValue) +{ + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast(theAttribute); + AttributePoint2DArrayPtr aPointArrayAttr = + std::dynamic_pointer_cast(theAttribute); + if (aPointAttr) + aPointAttr->setValue(theValue); + else if (aPointArrayAttr && thePointIndex >= 0) + aPointArrayAttr->setPnt(thePointIndex, theValue); +} -/// Global constraint manager object -SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== @@ -64,6 +108,7 @@ SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== SketchSolver_Manager* SketchSolver_Manager::instance() { + static SketchSolver_Manager* mySelf = 0; // Self pointer to implement singleton functionality if (!mySelf) mySelf = new SketchSolver_Manager(); return mySelf; @@ -80,8 +125,10 @@ SketchSolver_Manager::SketchSolver_Manager() Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)); + ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED)); + ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_GET_DOF_OBJECTS)); } SketchSolver_Manager::~SketchSolver_Manager() @@ -89,14 +136,9 @@ SketchSolver_Manager::~SketchSolver_Manager() myGroups.clear(); } -void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder) -{ - myBuilder = theBuilder; -} - -BuilderPtr SketchSolver_Manager::builder() +bool SketchSolver_Manager::groupMessages() { - return myBuilder; + return true; } // ============================================================================ @@ -106,502 +148,315 @@ BuilderPtr SketchSolver_Manager::builder() void SketchSolver_Manager::processEvent( const std::shared_ptr& theMessage) { - checkConflictingConstraints(theMessage); + bool needToResolve = false; + bool isUpdateFlushed = false; + bool isMovedEvt = false; + + static const Events_ID aCreatedEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); + static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED); + // sketch is prepared for resolve: all the needed events + // are collected and must be processed by the solver + if (theMessage->eventID() == aSketchPreparedEvent) { + flushGrouped(anUpdateEvent); + needToResolve = true; + } + if (myIsComputed) return; myIsComputed = true; - // Shows that the message has at least one feature applicable for solver - bool hasProperFeature = false; - - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) - || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) - || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + if (theMessage->eventID() == aCreatedEvent || theMessage->eventID() == anUpdateEvent) { std::shared_ptr anUpdateMsg = std::dynamic_pointer_cast(theMessage); - std::set aFeatures = anUpdateMsg->objects(); - - bool isUpdateFlushed = stopSendUpdate(); - - bool isMovedEvt = theMessage->eventID() - == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); - if (isMovedEvt) { - std::set::iterator aFeatIter; - for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { - std::shared_ptr aSFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (aSFeature) { - moveEntity(aSFeature); - hasProperFeature = true; - } - } - } else { - std::list aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures); - std::list::iterator aFeatIter = aSketchFeatures.begin(); - for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) { - if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) { - std::shared_ptr aSketch = - std::dynamic_pointer_cast(*aFeatIter); - hasProperFeature = changeWorkplane(aSketch) || hasProperFeature; - continue; - } - std::shared_ptr aFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (!aFeature) - continue; - hasProperFeature = changeFeature(aFeature) || hasProperFeature; - } + + isUpdateFlushed = stopSendUpdate(); + + // update sketch features only + const std::set& aFeatures = anUpdateMsg->objects(); + IndexedFeatureMap anOrderedFeatures; + CompositeFeaturePtr aSketchFeature; + // try to keep order as features were created if there are several created features: #2229 + if (theMessage->eventID() == aCreatedEvent && aFeatures.size() > 1) { + featuresOrderedByCreation(aFeatures, anOrderedFeatures); + } else { // order is not important, just process features before constraints + featuresOrderedByType(aFeatures, anOrderedFeatures, aSketchFeature); } - bool needToUpdate = false; - // Solve the set of constraints - if (hasProperFeature) - needToUpdate = resolveConstraints(); + IndexedFeatureMap::iterator aFeat; + for (aFeat = anOrderedFeatures.begin(); aFeat != anOrderedFeatures.end(); aFeat++) { + updateFeature(aFeat->second); + } + updateSketch(aSketchFeature); + + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + std::shared_ptr aMoveMsg = + std::dynamic_pointer_cast(theMessage); + + ObjectPtr aMovedObject = aMoveMsg->movedObject(); + AttributePtr aMovedAttribute = aMoveMsg->movedAttribute(); + int aMovedPoint = aMoveMsg->movedPointIndex(); + + const std::shared_ptr& aFrom = aMoveMsg->originalPosition(); + const std::shared_ptr& aTo = aMoveMsg->currentPosition(); - // Features may be updated => now send events, but for all changed at once - if (isUpdateFlushed) - allowSendUpdate(); - // send update for movement in any case - if (needToUpdate || isMovedEvt) - Events_Loop::loop()->flush(anUpdateEvent); + if (aMovedObject) { + FeaturePtr aMovedFeature = ModelAPI_Feature::feature(aMovedObject); + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(aMovedFeature); + if (aSketchFeature && !aSketchFeature->isMacro()) + needToResolve = moveFeature(aSketchFeature, aFrom, aTo); + } else if (aMovedAttribute) + needToResolve = moveAttribute(aMovedAttribute, aMovedPoint, aFrom, aTo); } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { std::shared_ptr aDeleteMsg = std::dynamic_pointer_cast(theMessage); - const std::set& aFeatureGroups = aDeleteMsg->groups(); + const std::list, std::string>>& aFeatureGroups = + aDeleteMsg->groups(); - // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch - std::set::const_iterator aFGrIter; + // Find SketchPlugin_Sketch::ID() in groups. + // The constraint groups should be updated when an object removed from Sketch + std::list, std::string>>::const_iterator aFGrIter; for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) - if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 || - aFGrIter->compare(ModelAPI_Feature::group()) == 0) + if (aFGrIter->second == ModelAPI_ResultConstruction::group() || + aFGrIter->second == ModelAPI_Feature::group()) break; if (aFGrIter != aFeatureGroups.end()) { - hasProperFeature = true; - std::list aGroupsToResolve; - std::list::iterator aGroupIter = myGroups.begin(); - std::list aSeparatedGroups; + std::list::iterator aGroupIter = myGroups.begin(); while (aGroupIter != myGroups.end()) { if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed - delete *aGroupIter; - std::list::iterator aRemoveIt = aGroupIter++; + std::list::iterator aRemoveIt = aGroupIter++; myGroups.erase(aRemoveIt); continue; } - if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group - (*aGroupIter)->splitGroup(aSeparatedGroups); - //if (!(*aGroupIter)->getWorkplane()->string( - // SketchPlugin_Sketch::SOLVER_ERROR())->value().empty()) - aGroupsToResolve.push_back(*aGroupIter); - } - aGroupIter++; - } - if (aSeparatedGroups.size() > 0) { - myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); - aGroupsToResolve.insert(aGroupsToResolve.end(), - aSeparatedGroups.begin(), aSeparatedGroups.end()); - } - if (!aGroupsToResolve.empty()) - resolveConstraints(aGroupsToResolve); + (*aGroupIter)->repairConsistency(); + ++aGroupIter; + } } + myIsComputed = false; } - - if (hasProperFeature) - degreesOfFreedom(); - myIsComputed = false; -} - -void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr& theMessage) -{ - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_SOLVER_REPAIRED)) { - std::shared_ptr aMessage = - std::dynamic_pointer_cast(theMessage); - std::set aSentObjs = aMessage->objects(); - if (!aSentObjs.empty()) { - // Obtain sketch where the constraints are placed. - // It is enough to check only one constraint. - CompositeFeaturePtr aSketch; - FeaturePtr aConstraint = ModelAPI_Feature::feature(*aSentObjs.begin()); - std::list::const_iterator aGrIt = myGroups.begin(); - for (; aGrIt != myGroups.end(); ++aGrIt) - if ((*aGrIt)->isInteract(aConstraint)) { - aSketch = (*aGrIt)->getWorkplane(); - break; - } - - // Search failed groups built on the same sketch - if (aSketch) { - for (aGrIt = myGroups.begin(); aGrIt != myGroups.end(); ++aGrIt) { - SketchSolver_Group* aGroup = *aGrIt; - if (aGroup->isBaseWorkplane(aSketch) && aGroup->isFailed() && - !aGroup->isInteract(aConstraint)) { - // reset error message on the sketch - aGroup->getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue( - SketchSolver_Error::CONSTRAINTS()); - break; + else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_GET_DOF_OBJECTS)) { + std::shared_ptr anUpdateMsg = + std::dynamic_pointer_cast(theMessage); + std::set aObjects = anUpdateMsg->objects(); + if (aObjects.size() == 1) { + std::set::const_iterator aIt; + for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) { + CompositeFeaturePtr aFeature = + std::dynamic_pointer_cast(*aIt); + if (aFeature) { + SketchGroupPtr aGroup = findGroup(aFeature); + + std::set aFreeFeatures; + aGroup->underconstrainedFeatures(aFreeFeatures); + + std::list aFeatures; + std::set::const_iterator aIt; + for (aIt = aFreeFeatures.cbegin(); aIt != aFreeFeatures.cend(); ++aIt) { + aFeatures.push_back(*aIt); } + + // send features to GUI + static const Events_ID anEvent = Events_Loop::eventByName(EVENT_DOF_OBJECTS); + ModelAPI_EventCreator::get()->sendUpdated(aFeatures, anEvent); + Events_Loop::loop()->flush(anEvent); } } } } + + // resolve constraints if needed + bool needToUpdate = needToResolve && resolveConstraints(); + releaseFeaturesIfEventsBlocked(); + + // Features may be updated => now send events, but for all changed at once + if (isUpdateFlushed) + allowSendUpdate(); + + myIsComputed = false; + + // send update for movement in any case + if (needToUpdate || isMovedEvt) + Events_Loop::loop()->flush(anUpdateEvent); } // ============================================================================ -// Function: changeWorkplane -// Purpose: update workplane by given parameters of the sketch +// Function: updateSketch +// Purpose: update sketch plane in appropriate group // ============================================================================ -bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) +bool SketchSolver_Manager::updateSketch(const CompositeFeaturePtr& theSketch) { - bool aResult = true; // changed when a workplane wrongly updated - bool isUpdated = false; - // Try to update specified workplane in all groups - std::list::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->isBaseWorkplane(theSketch)) { - isUpdated = true; - aResult = false; - } - // If the workplane is not updated, so this is a new workplane - if (!isUpdated) { - SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch); - // Verify that the group is created successfully - if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) { - delete aNewGroup; - return false; + if (!theSketch) + return true; + + bool isOk = true; + std::list::const_iterator aGroupIt; + for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt) + if ((*aGroupIt)->getWorkplane() == theSketch) { + (*aGroupIt)->updateSketch(theSketch); + break; } - myGroups.push_back(aNewGroup); - } - return aResult; + return isOk; } // ============================================================================ -// Function: changeConstraintOrEntity -// Purpose: create/update the constraint or the feature and place it into appropriate group +// Function: updateFeature +// Purpose: create/update constraint or feature in appropriate group // ============================================================================ -bool SketchSolver_Manager::changeFeature(std::shared_ptr theFeature) +bool SketchSolver_Manager::updateFeature(const std::shared_ptr& theFeature) { - // Search the groups which this feature touches - std::set aGroups; - findGroups(theFeature, aGroups); - - std::shared_ptr aConstraint = + // Check feature validity and find a group to place it. + // If the feature is not valid, the returned group will be empty. + // This will protect to deal with wrong (not fully initialized) features. + SketchGroupPtr aGroup = findGroup(theFeature); + if (!aGroup) + return false; + aGroup->blockEvents(true); + + std::shared_ptr aConstraint = std::dynamic_pointer_cast(theFeature); - // Process the groups list - if (aGroups.size() == 0) { - // There are no groups applicable for this constraint => create new one - // The group will be created only for constraints, not for features - if (!aConstraint) return false; - std::shared_ptr aWP = findWorkplane(aConstraint); - if (!aWP) - return false; - SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); - if (!aGroup->changeConstraint(aConstraint)) { - delete aGroup; - return false; - } - myGroups.push_back(aGroup); - return true; - } else if (aGroups.size() == 1) { // Only one group => add feature into it - GroupID aGroupId = *(aGroups.begin()); - std::list::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->getId() == aGroupId) { - // If the group is empty, the feature is not added (the constraint only) - if (!aConstraint && !(*aGroupIter)->isEmpty()) - return (*aGroupIter)->updateFeature(theFeature); - return (*aGroupIter)->changeConstraint(aConstraint); - } - } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them - std::set::const_iterator aGroupsIter = aGroups.begin(); - - // Search first group - std::list::iterator aFirstGroupIter; - for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++) - if ((*aFirstGroupIter)->getId() == *aGroupsIter) - break; - if (aFirstGroupIter == myGroups.end()) - return false; - - // Append other groups to the first one - std::list::iterator anOtherGroupIter = aFirstGroupIter; - ++anOtherGroupIter; - for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { - for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) - if ((*anOtherGroupIter)->getId() == *aGroupsIter) - break; - if (anOtherGroupIter == myGroups.end()) { // Group disappears - anOtherGroupIter = aFirstGroupIter; - ++anOtherGroupIter; - continue; - } + bool isOk = false; + if (aConstraint) + isOk = aGroup->changeConstraint(aConstraint); + else + isOk = aGroup->updateFeature(theFeature); + return isOk; +} - (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); - std::list::iterator aRemoveIt = anOtherGroupIter++; - delete *aRemoveIt; - myGroups.erase(aRemoveIt); +// ============================================================================ +// Function: moveFeature +// Purpose: move given feature in appropriate group +// ============================================================================ +bool SketchSolver_Manager::moveFeature( + const std::shared_ptr& theMovedFeature, + const std::shared_ptr& theFrom, + const std::shared_ptr& theTo) +{ + SketchGroupPtr aGroup = findGroup(theMovedFeature); + if (!aGroup) + return false; + + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theMovedFeature); + if (aConstraint) + { + std::shared_ptr aPntAttr = std::dynamic_pointer_cast + (aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT())); + if (aPntAttr) + { + aPntAttr->setValue(theTo); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); } - - if (aConstraint) - (*aFirstGroupIter)->changeConstraint(aConstraint); - else - (*aFirstGroupIter)->updateFeature(theFeature); - // groups are merged => need to resolve them return true; } - // Something goes wrong - return false; + aGroup->blockEvents(true); + return aGroup->moveFeature(theMovedFeature, theFrom, theTo); } // ============================================================================ -// Function: moveEntity -// Purpose: update element moved on the sketch, which is used by constraints +// Function: moveAttribute +// Purpose: move given attribute in appropriate group // ============================================================================ -void SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) +bool SketchSolver_Manager::moveAttribute( + const std::shared_ptr& theMovedAttribute, + const int theMovedPointIndex, + const std::shared_ptr& theFrom, + const std::shared_ptr& theTo) { - bool isMoved = false; - std::list::iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); aGroupIt++) - if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) { - (*aGroupIt)->moveFeature(theFeature); - isMoved = true; - } + FeaturePtr anOwner = ModelAPI_Feature::feature(theMovedAttribute->owner()); + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(anOwner); + if (aConstraint) + { + setPoint(theMovedAttribute, theMovedPointIndex, theTo); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + return true; + } - if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) { - // Workaround to move arc. - // If the arc has not been constrained, we will push it into empty group and apply movement. - for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++) - if ((*aGroupIt)->isEmpty()) - (*aGroupIt)->moveFeature(theFeature); + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(anOwner); + SketchGroupPtr aGroup; + if (aSketchFeature) + aGroup = findGroup(aSketchFeature); + if (!aGroup) { + setPoint(theMovedAttribute, theMovedPointIndex, theTo); + return false; } + + aGroup->blockEvents(true); + return aGroup->movePoint(theMovedAttribute, theMovedPointIndex, theFrom, theTo); } // ============================================================================ -// Function: findGroups +// Function: findGroup // Purpose: search groups of entities interacting with given feature // ============================================================================ -void SketchSolver_Manager::findGroups( - std::shared_ptr theFeature, - std::set& theGroupIDs) const +SketchGroupPtr SketchSolver_Manager::findGroup( + std::shared_ptr theFeature) { - std::shared_ptr aWP = findWorkplane(theFeature); - - SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint - std::list::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { - if (!(*aGroupIter)->isEmpty()) - theGroupIDs.insert((*aGroupIter)->getId()); - else if (!anEmptyGroup) - anEmptyGroup = *aGroupIter; + if (!isFeatureValid(theFeature)) + return SketchGroupPtr(); // do not process wrong features + + // Obtain sketch, containing the feature + CompositeFeaturePtr aSketch; + const std::set& aRefsList = theFeature->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefsList.begin(); + for (; aRefIt != aRefsList.end(); ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) { + aSketch = std::dynamic_pointer_cast(anOwner); + break; } - - // When only empty group is found, use it - if (anEmptyGroup && theGroupIDs.empty()) - theGroupIDs.insert(anEmptyGroup->getId()); + } + return findGroup(aSketch); } -// ============================================================================ -// Function: findWorkplane -// Purpose: search workplane containing given feature -// ============================================================================ -std::shared_ptr SketchSolver_Manager -::findWorkplane(std::shared_ptr theFeature) const +SketchGroupPtr SketchSolver_Manager::findGroup(CompositeFeaturePtr theSketch) { - // Already verified workplanes - std::set > aVerified; - - std::list::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { - std::shared_ptr aWP = (*aGroupIter)->getWorkplane(); - if (aVerified.find(aWP) != aVerified.end()) - continue; - - DataPtr aData = aWP->data(); - if (aData->isValid()) { - std::shared_ptr aWPFeatures = std::dynamic_pointer_cast< - ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID())); - std::list aFeaturesList = aWPFeatures->list(); - std::list::const_iterator anIter; - for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++) - if (*anIter == theFeature) - return aWP; // workplane is found - } - aVerified.insert(aWP); - } - - return std::shared_ptr(); + if (!theSketch) + return SketchGroupPtr(); // not a sketch's feature + + std::list::const_iterator aGroupIt; + for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt) + if ((*aGroupIt)->getWorkplane() == theSketch) + return *aGroupIt; + + // group for the sketch does not created yet + SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(theSketch)); + myGroups.push_back(aNewGroup); + return aNewGroup; } // ============================================================================ // Function: resolveConstraints // Purpose: change entities according to available constraints // ============================================================================ -bool SketchSolver_Manager::resolveConstraints(const std::list& theGroups) +bool SketchSolver_Manager::resolveConstraints() { bool needToUpdate = false; - const std::list& aGroupsToResolve = theGroups.empty() ? myGroups : theGroups; - std::list::const_iterator aGroupIter = aGroupsToResolve.begin(); - for (; aGroupIter != aGroupsToResolve.end(); aGroupIter++) + std::list::const_iterator aGroupIter = myGroups.begin(); + for (; aGroupIter != myGroups.end(); ++aGroupIter) { if ((*aGroupIter)->resolveConstraints()) needToUpdate = true; + } return needToUpdate; } -// ============================================================================ -// Function: degreesOfFreedom -// Purpose: calculate DoFs for each sketch -// ============================================================================ -void SketchSolver_Manager::degreesOfFreedom() +void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const { - static std::map aDoFDelta; // indicates how many DoF adds or decreases a feature - static bool isNeedInit = true; - if (isNeedInit) { - aDoFDelta[SketchPlugin_Point::ID()] = 2; - aDoFDelta[SketchPlugin_Line::ID()] = 4; - aDoFDelta[SketchPlugin_Circle::ID()] = 3; - aDoFDelta[SketchPlugin_Arc::ID()] = 5; - - aDoFDelta[SketchPlugin_ConstraintAngle::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintCollinear::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintDistance::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintEqual::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintHorizontal::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintLength::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintMiddle::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintParallel::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintPerpendicular::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintRadius::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintTangent::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintVertical::ID()] = -1; - - isNeedInit = false; - } - - std::map aSketchDoF; - - std::list::const_iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); ++aGroupIt) { - CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane(); - if (!aSketch->data()->isValid()) { - myDoF.erase(aSketch); - continue; - } - - // check conflicting constraints in the group - if ((*aGroupIt)->isFailed()) - aSketchDoF[aSketch] = -1; - // check the sketch is already processed - if (aSketchDoF.find(aSketch) != aSketchDoF.end() || aSketchDoF[aSketch] < 0) - continue; - - std::set aCoincidentPoints; - int aDoF = 0; - int aNbSubs = aSketch->numberOfSubs(); - for (int i = 0; i < aNbSubs; ++i) { - FeaturePtr aFeature = aSketch->subFeature(i); - // check DoF delta for invariant types - std::map::const_iterator aFound = aDoFDelta.find(aFeature->getKind()); - if (aFound != aDoFDelta.end()) { - aDoF += aFound->second; - continue; - } - - // DoF delta in specific cases - if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()}; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - bool isPoint = !aRefAttr->isObject(); - if (isPoint) - aCoincPoint[j] = aRefAttr->attr(); - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - isPoint = anAttr && anAttr->getKind() == SketchPlugin_Point::ID(); - if (isPoint) - aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); - } - } - if (aCoincPoint[0] && aCoincPoint[1]) { - // point-point coincidence - if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() || - aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end()) - aDoF -= 2; - } else - aDoF -= 1; - for (int j = 0; j < 2; ++j) - if (aCoincPoint[j]) - aCoincidentPoints.insert(aCoincPoint[j]); - } - else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); - assert(aRefAttr); - if (!aRefAttr->isObject()) - aDoF -= 2; // attribute is a point - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (anAttr) - aDoF -= aDoFDelta[anAttr->getKind()]; - } - } - else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() || - aFeature->getKind() == SketchPlugin_MultiRotation::ID() || - aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) { - int aNbCopies = 1; - std::string anAttrName; - if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID()) - anAttrName = SketchPlugin_Constraint::ENTITY_B(); - else { - if (aFeature->getKind() == SketchPlugin_MultiRotation::ID()) - aNbCopies = aFeature->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1; - else if (aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) - aNbCopies = aFeature->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1; - anAttrName = SketchPlugin_Constraint::ENTITY_A(); - } - - AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast( - aFeature->attribute(anAttrName)); - std::list anObjList = aRefListOfShapes->list(); - std::list::const_iterator anObjIt = anObjList.begin(); - for (; anObjIt != anObjList.end(); ++anObjIt) { - FeaturePtr aSub = ModelAPI_Feature::feature(*anObjIt); - aDoF -= aDoFDelta[aSub->getKind()] * aNbCopies; - } - } - } - - aSketchDoF[aSketch] = aDoF; - } - - // Check the degrees of freedom are changed - std::map::const_iterator aDoFIt = aSketchDoF.begin(); - std::map::iterator aFound; - for (; aDoFIt != aSketchDoF.end(); ++aDoFIt) { - if (aDoFIt->second < 0) - continue; // conflicting constraints on the current sketch - aFound = myDoF.find(aDoFIt->first); - if (aFound != myDoF.end() && aFound->second == aDoFIt->second) - continue; // nothing is changed - myDoF[aDoFIt->first] = aDoFIt->second; - // change attribute value - std::ostringstream aStream; - if (aDoFIt->second == 0) - aStream << "Sketch fully fixed (DOF = " << aDoFIt->second << ")"; - else - aStream << "DOF (degree of freedom) = " << aDoFIt->second; - aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStream.str()); - } + std::list::const_iterator aGroupIter = myGroups.begin(); + for (; aGroupIter != myGroups.end(); ++aGroupIter) + (*aGroupIter)->blockEvents(false); } bool SketchSolver_Manager::stopSendUpdate() const { +static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); // to avoid redisplay of each segment on update by solver one by one in the viewer bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); if (isUpdateFlushed) { @@ -612,5 +467,5 @@ bool SketchSolver_Manager::stopSendUpdate() const void SketchSolver_Manager::allowSendUpdate() const { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); + Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true); }