X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Manager.cpp;h=8e976d02b9dd8d370fc3f515ddd47be4e2c30900;hb=334029ee7a94867a1ed39d7ba51b6e49770b6e34;hp=442cf15c2ae1e6fde13251104c025f82c36e36d5;hpb=37c59d59b17e4a7e304588fb647488457a0c7283;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 442cf15c2..8e976d02b 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -1,38 +1,48 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Manager.cpp -// Created: 08 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_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 +/// Global constraint manager object +static SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); -// Initialization of constraint manager self pointer -SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; +/// \brief Verifies is the feature valid +static bool isFeatureValid(FeaturePtr theFeature) +{ + if (!theFeature || !theFeature->data() || !theFeature->data()->isValid()) + return false; + + SessionPtr aMgr = ModelAPI_Session::get(); + ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); + return aFactory->validate(theFeature); +} -/// Global constraint manager object -SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== @@ -40,6 +50,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; @@ -55,6 +66,10 @@ SketchSolver_Manager::SketchSolver_Manager() Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); 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_SKETCH_PREPARED)); } SketchSolver_Manager::~SketchSolver_Manager() @@ -62,14 +77,9 @@ SketchSolver_Manager::~SketchSolver_Manager() myGroups.clear(); } -void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder) +bool SketchSolver_Manager::groupMessages() { - myBuilder = theBuilder; -} - -BuilderPtr SketchSolver_Manager::builder() -{ - return myBuilder; + return true; } // ============================================================================ @@ -79,288 +89,281 @@ BuilderPtr SketchSolver_Manager::builder() void SketchSolver_Manager::processEvent( const std::shared_ptr& 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; - 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)) { + myIsComputed = true; + + if (theMessage->eventID() == aCreatedEvent || theMessage->eventID() == anUpdateEvent) { std::shared_ptr anUpdateMsg = std::dynamic_pointer_cast(theMessage); - std::set aFeatures = anUpdateMsg->objects(); - // Shows the message has at least one feature applicable for solver - bool hasProperFeature = false; + isUpdateFlushed = stopSendUpdate(); - bool isMovedEvt = theMessage->eventID() - == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); - if (isMovedEvt) { + // update sketch features only + const std::set& aFeatures = anUpdateMsg->objects(); + // try to keep order as features were created if there are several created features: #2229 + if (theMessage->eventID() == aCreatedEvent && aFeatures.size() > 1) { + std::map> anOrderedFeatures; std::set::iterator aFeatIter; for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { - std::shared_ptr aSFeature = + std::shared_ptr aFeature = std::dynamic_pointer_cast(*aFeatIter); - if (aSFeature) { - moveEntity(aSFeature); - hasProperFeature = true; + if (aFeature && !aFeature->isMacro() && aFeature->data() && aFeature->data()->isValid()) { + anOrderedFeatures[aFeature->data()->featureId()] = aFeature; } } - } 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::map>::iterator aFeat; + for(aFeat = anOrderedFeatures.begin(); aFeat != anOrderedFeatures.end(); aFeat++) { + updateFeature(aFeat->second); + } + } else { // order is not important + std::set::iterator aFeatIter; + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + std::shared_ptr aFeature = std::dynamic_pointer_cast(*aFeatIter); - if (!aFeature) - continue; - hasProperFeature = changeFeature(aFeature) || hasProperFeature; + if (aFeature && !aFeature->isMacro()) + updateFeature(aFeature); } } - // Solve the set of constraints - if (hasProperFeature) - resolveConstraints(isMovedEvt); // send update for movement in any case + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + std::shared_ptr aMoveMsg = + std::dynamic_pointer_cast(theMessage); + + ObjectPtr aMovedObject = aMoveMsg->movedObject(); + std::shared_ptr aMovedPoint = + std::dynamic_pointer_cast(aMoveMsg->movedAttribute()); + + const std::shared_ptr& aFrom = aMoveMsg->originalPosition(); + const std::shared_ptr& aTo = aMoveMsg->currentPosition(); + + 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 (aMovedPoint) + needToResolve = moveAttribute(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()) { - std::vector::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; - int aShift = aGroupIter - myGroups.begin(); - myGroups.erase(aGroupIter); - aGroupIter = myGroups.begin() + aShift; + std::list::iterator aRemoveIt = aGroupIter++; + myGroups.erase(aRemoveIt); continue; } - if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group - (*aGroupIter)->splitGroup(aSeparatedGroups); - } - aGroupIter++; + + (*aGroupIter)->repairConsistency(); + ++aGroupIter; } - if (aSeparatedGroups.size() > 0) - myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); } + myIsComputed = false; } + + // 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: updateFeature +// Purpose: create/update constraint or feature in appropriate group // ============================================================================ -bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) +bool SketchSolver_Manager::updateFeature(const std::shared_ptr& theFeature) { - bool aResult = true; // changed when a workplane wrongly updated - bool isUpdated = false; - // Try to update specified workplane in all groups - std::vector::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; - } - myGroups.push_back(aNewGroup); - } - return aResult; + // 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); + + bool isOk = false; + if (aConstraint) + isOk = aGroup->changeConstraint(aConstraint); + else + isOk = aGroup->updateFeature(theFeature); + return isOk; } // ============================================================================ -// Function: changeConstraintOrEntity -// Purpose: create/update the constraint or the feature and place it into appropriate group +// Function: moveFeature +// Purpose: move given feature in appropriate group // ============================================================================ -bool SketchSolver_Manager::changeFeature(std::shared_ptr theFeature) +bool SketchSolver_Manager::moveFeature( + const std::shared_ptr& theMovedFeature, + const std::shared_ptr& theFrom, + const std::shared_ptr& theTo) { - // Search the groups which this feature touches - std::set aGroups; - findGroups(theFeature, aGroups); - - 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; + 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)); } - myGroups.push_back(aGroup); return true; - } else if (aGroups.size() == 1) { // Only one group => add feature into it - GroupID aGroupId = *(aGroups.begin()); - std::vector::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::vector::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::vector::iterator anOtherGroupIter = aFirstGroupIter + 1; - for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { - for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) - if ((*anOtherGroupIter)->getId() == *aGroupsIter) - break; - if (anOtherGroupIter == myGroups.end()) { // Group disappears - anOtherGroupIter = aFirstGroupIter + 1; - continue; - } - - (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); - int aShiftFirst = aFirstGroupIter - myGroups.begin(); - int aShiftOther = anOtherGroupIter - myGroups.begin(); - delete *anOtherGroupIter; - myGroups.erase(anOtherGroupIter); - aFirstGroupIter = myGroups.begin() + aShiftFirst; - anOtherGroupIter = myGroups.begin() + aShiftOther; - } - - if (aConstraint) - return (*aFirstGroupIter)->changeConstraint(aConstraint); - return (*aFirstGroupIter)->updateFeature(theFeature); } - // 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 std::shared_ptr& theFrom, + const std::shared_ptr& theTo) { - std::vector::iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); aGroupIt++) - if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) - (*aGroupIt)->moveFeature(theFeature); -} + FeaturePtr anOwner = ModelAPI_Feature::feature(theMovedAttribute->owner()); + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(anOwner); + if (aConstraint) + { + theMovedAttribute->setValue(theTo); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + return true; + } -// ============================================================================ -// Function: findGroups -// Purpose: search groups of entities interacting with given feature -// ============================================================================ -void SketchSolver_Manager::findGroups( - std::shared_ptr theFeature, - std::set& theGroupIDs) const -{ - std::shared_ptr aWP = findWorkplane(theFeature); - - SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint - std::vector::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; - } + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(anOwner); + SketchGroupPtr aGroup; + if (aSketchFeature) + aGroup = findGroup(aSketchFeature); + if (!aGroup) { + theMovedAttribute->setValue(theTo); + return false; + } - // When only empty group is found, use it - if (anEmptyGroup && theGroupIDs.empty()) - theGroupIDs.insert(anEmptyGroup->getId()); + aGroup->blockEvents(true); + return aGroup->movePoint(theMovedAttribute, theFrom, theTo); } // ============================================================================ -// Function: findWorkplane -// Purpose: search workplane containing given feature +// Function: findGroup +// Purpose: search groups of entities interacting with given feature // ============================================================================ -std::shared_ptr SketchSolver_Manager -::findWorkplane(std::shared_ptr theFeature) const +SketchGroupPtr SketchSolver_Manager::findGroup( + std::shared_ptr theFeature) { - // Already verified workplanes - std::set > aVerified; - - std::vector::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 + 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; } - aVerified.insert(aWP); } - return std::shared_ptr(); + if (!aSketch) + return SketchGroupPtr(); // not a sketch's feature + + std::list::const_iterator aGroupIt; + for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt) + if ((*aGroupIt)->getWorkplane() == aSketch) + return *aGroupIt; + + // group for the sketch does not created yet + SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch)); + myGroups.push_back(aNewGroup); + return aNewGroup; } // ============================================================================ // Function: resolveConstraints // Purpose: change entities according to available constraints // ============================================================================ -void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate) +bool SketchSolver_Manager::resolveConstraints() { - myIsComputed = true; bool needToUpdate = false; - static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + std::list::const_iterator aGroupIter = myGroups.begin(); + for (; aGroupIter != myGroups.end(); ++aGroupIter) { + if ((*aGroupIter)->resolveConstraints()) + needToUpdate = true; + } + return needToUpdate; +} + +void SketchSolver_Manager::releaseFeaturesIfEventsBlocked() const +{ + 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) { Events_Loop::loop()->setFlushed(anUpdateEvent, false); } + return isUpdateFlushed; +} - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->resolveConstraints()) - needToUpdate = true; - - // Features may be updated => now send events, but for all changed at once - if (isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); - } - // Must be before flush because on "Updated" flush the results may be produced - // and the creation event is appeared with many new objects. If myIsComputed these - // events are missed in processEvents and some elements are not added. - myIsComputed = false; - if (needToUpdate || theForceUpdate) - Events_Loop::loop()->flush(anUpdateEvent); +void SketchSolver_Manager::allowSendUpdate() const +{ + Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true); }