X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Manager.cpp;h=8bebc53c4247037984ef7b9c14fb112e7c6903f4;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=0d20365a4d8243ed11af416daa8579fb9a11cd87;hpb=e066abaa17e20d15934c0c83cdd8de07ffd93122;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 0d20365a4..8bebc53c4 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -1,13 +1,28 @@ -// 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 @@ -28,6 +43,64 @@ static bool isFeatureValid(FeaturePtr theFeature) 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); +} + // ======================================================== @@ -55,6 +128,7 @@ SketchSolver_Manager::SketchSolver_Manager() ////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() @@ -62,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; @@ -84,76 +148,79 @@ 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 if (theMessage->eventID() == aSketchPreparedEvent) { flushGrouped(anUpdateEvent); - return; + needToResolve = true; } if (myIsComputed) return; myIsComputed = true; - 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); - - // Shows that the message has at least one feature applicable for solver - bool hasProperFeature = false; + isUpdateFlushed = stopSendUpdate(); // update sketch features only - std::set::iterator aFeatIter; - for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { - std::shared_ptr aFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (!aFeature || aFeature->isMacro()) - continue; - - hasProperFeature = updateFeature(aFeature, isMovedEvt) || hasProperFeature; + 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); } - if (isMovedEvt && !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; + IndexedFeatureMap::iterator aFeat; + for (aFeat = anOrderedFeatures.begin(); aFeat != anOrderedFeatures.end(); aFeat++) { + updateFeature(aFeat->second); } + updateSketch(aSketchFeature); - // Solve the set of constraints - bool needToUpdate = resolveConstraints(); + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + std::shared_ptr aMoveMsg = + std::dynamic_pointer_cast(theMessage); - // Features may be updated => now send events, but for all changed at once - if (isUpdateFlushed) - allowSendUpdate(); + ObjectPtr aMovedObject = aMoveMsg->movedObject(); + AttributePtr aMovedAttribute = aMoveMsg->movedAttribute(); + int aMovedPoint = aMoveMsg->movedPointIndex(); - myIsComputed = false; + const std::shared_ptr& aFrom = aMoveMsg->originalPosition(); + const std::shared_ptr& aTo = aMoveMsg->currentPosition(); - // 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; + 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()) { @@ -168,19 +235,78 @@ void SketchSolver_Manager::processEvent( (*aGroupIter)->repairConsistency(); ++aGroupIter; } - - resolveConstraints(); } myIsComputed = false; } + 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: changeConstraintOrEntity -// Purpose: create/update the constraint or the feature and place it into appropriate group +// Function: updateSketch +// Purpose: update sketch plane in appropriate group // ============================================================================ -bool SketchSolver_Manager::updateFeature(std::shared_ptr theFeature, - bool theMoved) +bool SketchSolver_Manager::updateSketch(const CompositeFeaturePtr& theSketch) +{ + 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; + } + return isOk; +} + +// ============================================================================ +// Function: updateFeature +// Purpose: create/update constraint or feature in appropriate group +// ============================================================================ +bool SketchSolver_Manager::updateFeature(const std::shared_ptr& theFeature) { // Check feature validity and find a group to place it. // If the feature is not valid, the returned group will be empty. @@ -196,19 +322,82 @@ bool SketchSolver_Manager::updateFeature(std::shared_ptr t bool isOk = false; if (aConstraint) isOk = aGroup->changeConstraint(aConstraint); - else if (theMoved) - isOk = aGroup->moveFeature(theFeature); else isOk = aGroup->updateFeature(theFeature); return isOk; } +// ============================================================================ +// 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)); + } + return true; + } + + aGroup->blockEvents(true); + return aGroup->moveFeature(theMovedFeature, theFrom, theTo); +} + +// ============================================================================ +// Function: moveAttribute +// Purpose: move given attribute in appropriate group +// ============================================================================ +bool SketchSolver_Manager::moveAttribute( + const std::shared_ptr& theMovedAttribute, + const int theMovedPointIndex, + const std::shared_ptr& theFrom, + const std::shared_ptr& theTo) +{ + 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; + } + + 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: findGroup // Purpose: search groups of entities interacting with given feature // ============================================================================ SketchGroupPtr SketchSolver_Manager::findGroup( - std::shared_ptr theFeature) + std::shared_ptr theFeature) { if (!isFeatureValid(theFeature)) return SketchGroupPtr(); // do not process wrong features @@ -224,17 +413,21 @@ SketchGroupPtr SketchSolver_Manager::findGroup( break; } } + return findGroup(aSketch); +} - if (!aSketch) +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() == aSketch) + if ((*aGroupIt)->getWorkplane() == theSketch) return *aGroupIt; // group for the sketch does not created yet - SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch)); + SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(theSketch)); myGroups.push_back(aNewGroup); return aNewGroup; } @@ -250,11 +443,17 @@ bool SketchSolver_Manager::resolveConstraints() for (; aGroupIter != myGroups.end(); ++aGroupIter) { if ((*aGroupIter)->resolveConstraints()) needToUpdate = true; - (*aGroupIter)->blockEvents(false); } 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);