X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Manager.cpp;h=8bebc53c4247037984ef7b9c14fb112e7c6903f4;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=2449d61c0bede9df7f75cc92cb5cb3d47de24e0d;hpb=876df3f1e552699e9bea75c48245e92e1bedd81e;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 2449d61c0..8bebc53c4 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -1,65 +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(); // ======================================================== @@ -67,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; @@ -79,13 +121,14 @@ SketchSolver_Manager::SketchSolver_Manager() // Register in event loop Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->registerListener(this, anUpdateEvent); + 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_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() @@ -93,16 +136,6 @@ SketchSolver_Manager::~SketchSolver_Manager() myGroups.clear(); } -void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder) -{ - myBuilder = theBuilder; -} - -BuilderPtr SketchSolver_Manager::builder() -{ - return myBuilder; -} - bool SketchSolver_Manager::groupMessages() { return true; @@ -115,746 +148,315 @@ bool SketchSolver_Manager::groupMessages() 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 + // sketch is prepared for resolve: all the needed events + // are collected and must be processed by the solver if (theMessage->eventID() == aSketchPreparedEvent) { flushGrouped(anUpdateEvent); - return; + needToResolve = true; } - checkConflictingConstraints(theMessage); - 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() == anUpdateEvent - || 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)) { - // Want to avoid recalculation of DoF too frequently. - // So, set the flag when the feature is really moved. - hasProperFeature = true; - } - } - if (!hasProperFeature) // in this iteration it will compute nothing, so, no problem with recursion - // it is important that solver flushes signal updated after processing move signal as there is - // optimization that relies on this update, might be found by key "optimization" - myIsComputed = false; - } 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); - // Features may be updated => now send events, but for all changed at once - if (isUpdateFlushed) - allowSendUpdate(); + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + std::shared_ptr aMoveMsg = + std::dynamic_pointer_cast(theMessage); - myIsComputed = false; + ObjectPtr aMovedObject = aMoveMsg->movedObject(); + AttributePtr aMovedAttribute = aMoveMsg->movedAttribute(); + int aMovedPoint = aMoveMsg->movedPointIndex(); - // send update for movement in any case - if (needToUpdate || isMovedEvt) - Events_Loop::loop()->flush(anUpdateEvent); + 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 (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() || - (*aGroupIter)->isFailed()) - 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(); -} - -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 || isUpdated; + 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; - } - - (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); - std::list::iterator aRemoveIt = anOtherGroupIter++; - delete *aRemoveIt; - myGroups.erase(aRemoveIt); - } - - if (aConstraint) - (*aFirstGroupIter)->changeConstraint(aConstraint); - else - (*aFirstGroupIter)->updateFeature(theFeature); - // groups are merged => need to resolve them - return true; - } - - // Something goes wrong - return false; + bool isOk = false; + if (aConstraint) + isOk = aGroup->changeConstraint(aConstraint); + else + isOk = aGroup->updateFeature(theFeature); + return isOk; } // ============================================================================ -// Function: moveEntity -// Purpose: update element moved on the sketch, which is used by constraints +// Function: moveFeature +// Purpose: move given feature in appropriate group // ============================================================================ -bool SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) +bool SketchSolver_Manager::moveFeature( + const std::shared_ptr& theMovedFeature, + 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)) - isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; - - 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. - bool hasEmptyGroup = false; - for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++) - if ((*aGroupIt)->isEmpty()) { - isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; - hasEmptyGroup = true; - } - // There is no empty group, create it explicitly - if (!hasEmptyGroup) { - // find sketch containing the arc - CompositeFeaturePtr aWP; - const std::set& aRefs = theFeature->data()->refsToMe(); - std::set::const_iterator aRefIt = aRefs.begin(); - for (; aRefIt != aRefs.end(); ++aRefIt) { - FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); - if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) { - aWP = std::dynamic_pointer_cast(anOwner); - break; - } - } - if (aWP) { - SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); - isMoved = aGroup->moveFeature(theFeature) || isMoved; - myGroups.push_back(aGroup); - } + 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)); } + return true; } - return isMoved; + + aGroup->blockEvents(true); + return aGroup->moveFeature(theMovedFeature, theFrom, theTo); } // ============================================================================ -// Function: findGroups -// Purpose: search groups of entities interacting with given feature +// Function: moveAttribute +// Purpose: move given attribute in appropriate group // ============================================================================ -void SketchSolver_Manager::findGroups( - std::shared_ptr theFeature, - std::set& theGroupIDs) const +bool SketchSolver_Manager::moveAttribute( + const std::shared_ptr& theMovedAttribute, + const int theMovedPointIndex, + const std::shared_ptr& theFrom, + const std::shared_ptr& theTo) { - 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; - } + 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; + } - // When only empty group is found, use it - if (anEmptyGroup && theGroupIDs.empty()) - theGroupIDs.insert(anEmptyGroup->getId()); + 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: 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::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 + 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 findGroup(aSketch); +} - return std::shared_ptr(); +SketchGroupPtr SketchSolver_Manager::findGroup(CompositeFeaturePtr theSketch) +{ + 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; -} - - -// Obtain points and their copies for Mirror, Multi-Rotation and Multi-Translation constraints -static void collectPointsAndCopies(FeaturePtr theConstraint, std::list >& thePoints) -{ - typedef std::list strlist; - static strlist aPointAttributes(1, SketchPlugin_Point::COORD_ID()); - static strlist aLineAttributes; - if (aLineAttributes.empty()) { - aLineAttributes.push_back(SketchPlugin_Line::START_ID()); - aLineAttributes.push_back(SketchPlugin_Line::END_ID()); - }; - static strlist aCircleAttributes(1, SketchPlugin_Circle::CENTER_ID()); - static strlist anArcAttributes; - if (anArcAttributes.empty()) { - anArcAttributes.push_back(SketchPlugin_Arc::CENTER_ID()); - anArcAttributes.push_back(SketchPlugin_Arc::START_ID()); - anArcAttributes.push_back(SketchPlugin_Arc::END_ID()); - }; - - static std::map aFeatureAttributes; - if (aFeatureAttributes.empty()) { - aFeatureAttributes[SketchPlugin_Point::ID()] = aPointAttributes; - aFeatureAttributes[SketchPlugin_Line::ID()] = aLineAttributes; - aFeatureAttributes[SketchPlugin_Circle::ID()] = aCircleAttributes; - aFeatureAttributes[SketchPlugin_Arc::ID()] = anArcAttributes; - } - - - std::set aPoints; - if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { - AttributeRefListPtr aBaseRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); - AttributeRefListPtr aMirrRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_C()); - - std::list aBaseList = aBaseRefList->list(); - std::list aMirrList = aMirrRefList->list(); - std::list::const_iterator aBIt, aMIt; - for (aBIt = aBaseList.begin(), aMIt = aMirrList.begin(); - aBIt != aBaseList.end() && aMIt != aMirrList.end(); ++aBIt, ++aMIt) { - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aBIt); - FeaturePtr aMirrFeature = ModelAPI_Feature::feature(*aMIt); - - strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; - strlist::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - aPoints.clear(); - aPoints.insert(aBaseFeature->attribute(*anIt)); - aPoints.insert(aMirrFeature->attribute(*anIt)); - thePoints.push_back(aPoints); - } - } } - else { // the "Multi" constraints - std::string aNbObjName; - if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) - aNbObjName = SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID(); - else - aNbObjName = SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID(); - int aNbCopies = theConstraint->integer(aNbObjName)->value(); - - AttributeRefListPtr aRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); - std::list aFullList = aRefList->list(); - std::list::const_iterator anObjIt = aFullList.begin(); - std::list::const_iterator aCopyIt; - while (anObjIt != aFullList.end()) { - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*anObjIt); - strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; - strlist::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - aPoints.clear(); - aCopyIt = anObjIt; - for (int i = 0; i < aNbCopies && aCopyIt != aFullList.end(); ++i, ++aCopyIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*aCopyIt); - aPoints.insert(aFeature->attribute(*anIt)); - } - thePoints.push_back(aPoints); - } - anObjIt = aCopyIt; - } - } -} - - -// returns true if the feature is external -static bool isExternal(const FeaturePtr& theFeature) -{ - AttributeSelectionPtr anAttr = theFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); - return anAttr && anAttr->context() && !anAttr->isInvalid(); + 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_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(); - bool isSketchValid = aSketch->data() && aSketch->data()->isValid(); - - if (isSketchValid) { - std::shared_ptr aNormal = - std::dynamic_pointer_cast(aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); - isSketchValid = aNormal && aNormal->isInitialized(); - } - - if (!isSketchValid) { - 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; - std::set aFixedPoints; - std::map > aPointOnLine; - std::list > aPointsInMultiConstraints; - int aDoF = 0; - int aNbSubs = aSketch->numberOfSubs(); - for (int i = 0; i < aNbSubs; ++i) { - FeaturePtr aFeature = aSketch->subFeature(i); - // do not change DoF for external feature - if (isExternal(aFeature)) - continue; - // 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()}; - FeaturePtr aCoincLine; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - if (!aRefAttr->isObject()) - aCoincPoint[j] = aRefAttr->attr(); - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (!anAttr) - continue; - if (anAttr->getKind() == SketchPlugin_Point::ID()) - aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); - else if (anAttr->getKind() == SketchPlugin_Line::ID()) - aCoincLine = anAttr; - } - } - if (aCoincPoint[0] && aCoincPoint[1]) { - bool isDoFDecreased = false; - // point-point coincidence - if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() || - aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end()) { - aDoF -= 2; - isDoFDecreased = true; - } - // check the coincident point is used in "multi" constraints - std::list >::const_iterator - aPtIt = aPointsInMultiConstraints.begin(); - bool isFound[2] = {false, false}; - for (; aPtIt != aPointsInMultiConstraints.end(); ++aPtIt) { - if ((!isFound[0] && (isFound[0] = (aPtIt->find(aCoincPoint[0]) != aPtIt->end()))) - || (!isFound[1] && (isFound[1] = (aPtIt->find(aCoincPoint[1]) != aPtIt->end())))) - aCoincidentPoints.insert(aPtIt->begin(), aPtIt->end()); - if (isFound[0] && isFound[1]) - break; - } - // check both points are fixed => not need to decrease DoF - bool isFixed[2] = { aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end(), - aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() }; - if (isFixed[0] && isFixed[1] && isDoFDecreased) - aDoF += 2; // revert decrease of DoF - else if (isFixed[0] && !isFixed[1]) - aFixedPoints.insert(aCoincPoint[1]); - else if (!isFixed[0] && isFixed[1]) - aFixedPoints.insert(aCoincPoint[0]); - } else { - aDoF -= 1; - if (aCoincPoint[0] && aCoincLine) { - // if the point is already coincident to a line (by middle point constraint), do not decrease DoF - std::map >::iterator - aPtFound = aPointOnLine.find(aCoincPoint[0]); - if (aPtFound != aPointOnLine.end() && - aPtFound->second.find(aCoincLine) != aPtFound->second.end()) - aDoF += 1; // restore value decreased above - else - aPointOnLine[aCoincPoint[0]].insert(aCoincLine); - } - } - for (int j = 0; j < 2; ++j) - if (aCoincPoint[j]) - aCoincidentPoints.insert(aCoincPoint[j]); - } - else if (aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) { - AttributePtr aPoint; - FeaturePtr aLine; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - if (aRefAttr->isObject()) - aLine = ModelAPI_Feature::feature(aRefAttr->object()); - else - aPoint = aRefAttr->attr(); - } - if (aPoint && aLine) { - // if the point is already on the line, decrease 1 DoF, instead decrease 2 DoF - std::map >::iterator - aPtFound = aPointOnLine.find(aPoint); - if (aPtFound != aPointOnLine.end() && - aPtFound->second.find(aLine) != aPtFound->second.end()) - aDoF -= 1; - else { - aDoF -= 2; - aPointOnLine[aPoint].insert(aLine); - } - } - } - else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); - assert(aRefAttr); - std::set aPoints; - if (!aRefAttr->isObject()) { - aDoF -= 2; // attribute is a point - aPoints.insert(aRefAttr->attr()); - } else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (anAttr) { - if (isExternal(anAttr)) - continue; // feature is already fixed since it is external - aDoF -= aDoFDelta[anAttr->getKind()]; - std::list aPtAttrs = anAttr->data()->attributes(GeomDataAPI_Point2D::typeId()); - aPoints.insert(aPtAttrs.begin(), aPtAttrs.end()); - } - } - - // Check whether feature's points are already coincident with fixed points. - // In this case we need to revert decrease of DoF for these points. - // If the coordinates of fixed points are different, it will be processed by solver. - for (int k = 0; k < i; ++k) { - FeaturePtr aFeature = aSketch->subFeature(k); - if (aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) - continue; - 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; - if (!aRefAttr->isObject()) - aCoincPoint[j] = aRefAttr->attr(); - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (anAttr && anAttr->getKind() == SketchPlugin_Point::ID()) - aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); - } - } - if (aCoincPoint[0] && aCoincPoint[1]) { - if ((aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end() && - aPoints.find(aCoincPoint[1]) != aPoints.end()) || - (aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() && - aPoints.find(aCoincPoint[0]) != aPoints.end())) - aDoF += 2; // point already fixed - } - } - // store fixed points - aFixedPoints.insert(aPoints.begin(), aPoints.end()); - } - 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; - } - // collect points and their copies for correct calculation of DoF for coincident points - collectPointsAndCopies(aFeature, aPointsInMultiConstraints); - } - } - - 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) { @@ -865,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); }