X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintManager.cpp;h=6cad183e4525abf4cba2cfb13a08b91d88fac7db;hb=9e869ede4d8c56262bb20534543c2bf56cd6a91b;hp=bf9ad5e101ab3fb092cb81a3ab9246f0ce64ab79;hpb=747ac7d5b70659aadafc432924b50fc74b5ff31d;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp index bf9ad5e10..6cad183e4 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -5,43 +5,29 @@ #include "SketchSolver_ConstraintManager.h" #include -#include -#include -#include #include #include #include -#include +#include +#include +#include + #include -#include + +#include +#include #include #include #include -#include - -/// Tolerance for value of parameters -const double tolerance = 1.e-10; +#include // Initialization of constraint manager self pointer SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0; -/// Global constaint manager object +/// Global constraint manager object SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance(); -/// This value is used to give unique index to the groups -static Slvs_hGroup myGroupIndexer = 0; - -/** \brief Search the entity/parameter with specified ID in the list of elements - * \param[in] theEntityID unique ID of the element - * \param[in] theEntities list of elements - * \return position of the found element or -1 if the element is not found - */ -template -static int Search(const uint32_t& theEntityID, const std::vector& theEntities); - - - // ======================================================== // ========= SketchSolver_ConstraintManager =============== // ======================================================== @@ -55,11 +41,13 @@ SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance() SketchSolver_ConstraintManager::SketchSolver_ConstraintManager() { myGroups.clear(); + myIsComputed = false; // Register in event loop - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); + 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)); } SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager() @@ -67,85 +55,116 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager() myGroups.clear(); } -void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage) +// ============================================================================ +// Function: processEvent +// Class: SketchSolver_Session +// Purpose: listen the event loop and process the message +// ============================================================================ +void SketchSolver_ConstraintManager::processEvent( + const std::shared_ptr& theMessage) { - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) || - theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED)) - { - const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast(theMessage); - - // Only sketches and constraints can be added by Create event - boost::shared_ptr aSketch = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - if (aSketch) - { - changeWorkplane(aSketch); - return ; - } - boost::shared_ptr aConstraint = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - if (aConstraint) - { - changeConstraint(aConstraint); - - // Solve the set of constraints - resolveConstraints(); - return ; - } - - // Sketch plugin features only can be updated - boost::shared_ptr aFeature = - boost::dynamic_pointer_cast(aUpdateMsg->feature()); - if (aFeature) - { - updateEntity(aFeature); - - // Solve the set of constraints - resolveConstraints(); + 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)) { + std::shared_ptr anUpdateMsg = + std::dynamic_pointer_cast(theMessage); + std::set aFeatures = anUpdateMsg->objects(); + + 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) + updateEntity(aSFeature); + } + } else { + std::set::iterator aFeatIter; + // iterate sketchers fisrt to create all sketches before (on load may exist several sketches) + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + FeaturePtr aFeature = std::dynamic_pointer_cast(*aFeatIter); + if (!aFeature) + continue; + const std::string& aFeatureKind = aFeature->getKind(); + if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0) { + std::shared_ptr aSketch = std::dynamic_pointer_cast< + ModelAPI_CompositeFeature>(aFeature); + changeWorkplane(aSketch); + } + } + // then get anything but not the sketch + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (!aFeature) + continue; + changeConstraintOrEntity(aFeature); + } } - } - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED)) - { - const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast(theMessage); - if (aDeleteMsg->group().compare("Sketch") == 0) - { + // Solve the set of constraints + resolveConstraints(); + } 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(); + + // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch + std::set::const_iterator aFGrIter; + for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) + if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 || + aFGrIter->compare(ModelAPI_Feature::group()) == 0) + break; + + if (aFGrIter != aFeatureGroups.end()) { std::vector::iterator aGroupIter = myGroups.begin(); - while (aGroupIter != myGroups.end()) - { - if ((*aGroupIter)->updateGroup()) - { // the group should be removed + std::vector aSeparatedGroups; + 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; + continue; } - else aGroupIter++; + if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group + (*aGroupIter)->splitGroup(aSeparatedGroups); + } + aGroupIter++; } + if (aSeparatedGroups.size() > 0) + myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); } } } -bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr theSketch) +// ============================================================================ +// Function: changeWorkplane +// Class: SketchSolver_Session +// Purpose: update workplane by given parameters of the sketch +// ============================================================================ +bool SketchSolver_ConstraintManager::changeWorkplane( + std::shared_ptr theSketch) { - bool aResult = true; // changed when a workplane wrongly updated + 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)) - { + if ((*aGroupIter)->isBaseWorkplane(theSketch)) { isUpdated = true; if (!(*aGroupIter)->updateWorkplane()) aResult = false; } // If the workplane is not updated, so this is a new workplane - if (!isUpdated) - { + if (!isUpdated) { SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch); // Verify that the group is created successfully - if (!aNewGroup->isBaseWorkplane(theSketch)) - { + if (!aNewGroup->isBaseWorkplane(theSketch)) { delete aNewGroup; return false; } @@ -154,679 +173,210 @@ bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr theConstraint) +// ============================================================================ +// Function: changeConstraintOrEntity +// Class: SketchSolver_Session +// Purpose: create/update the constraint or the feature and place it into appropriate group +// ============================================================================ +bool SketchSolver_ConstraintManager::changeConstraintOrEntity( + std::shared_ptr theFeature) { - // Search the groups which this constraint touchs - std::vector aGroups; - findGroups(theConstraint, aGroups); + // 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 - boost::shared_ptr aWP = findWorkplaneForConstraint(theConstraint); - if (!aWP) return false; + 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_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP); - if (!aGroup->changeConstraint(theConstraint)) - { + if (!aGroup->changeConstraint(aConstraint)) { delete aGroup; return false; } myGroups.push_back(aGroup); return true; - } - else if (aGroups.size() == 1) - { // Only one group => add constraint into it + } else if (aGroups.size() == 1) { // Only one group => add feature into it Slvs_hGroup aGroupId = *(aGroups.begin()); std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->getId() == aGroupId) - return (*aGroupIter)->changeConstraint(theConstraint); - } - else if (aGroups.size() > 1) - { // Several groups applicable for this constraint => need to merge them - /// \todo Implement merging of groups + if ((*aGroupIter)->getId() == aGroupId) { + // If the group is empty, the feature is not added (the constraint only) + if (!aConstraint && !(*aGroupIter)->isEmpty()) + return (*aGroupIter)->changeEntity(theFeature) != SLVS_E_UNKNOWN; + 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)->changeEntity(theFeature) != SLVS_E_UNKNOWN; } // Something goes wrong return false; } -void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr theFeature) +// ============================================================================ +// Function: updateEntity +// Class: SketchSolver_Session +// Purpose: update any element on the sketch, which is used by constraints +// ============================================================================ +void SketchSolver_ConstraintManager::updateEntity( + std::shared_ptr theFeature) { // Create list of attributes depending on type of the feature std::vector anAttrList; + const std::string& aFeatureKind = theFeature->getKind(); // Point - boost::shared_ptr aPoint = - boost::dynamic_pointer_cast(theFeature); - if (aPoint) - anAttrList.push_back(POINT_ATTR_COORD); + if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) + anAttrList.push_back(SketchPlugin_Point::COORD_ID()); // Line - boost::shared_ptr aLine = - boost::dynamic_pointer_cast(theFeature); - if (aLine) - { - anAttrList.push_back(LINE_ATTR_START); - anAttrList.push_back(LINE_ATTR_END); + else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { + anAttrList.push_back(SketchPlugin_Line::START_ID()); + anAttrList.push_back(SketchPlugin_Line::END_ID()); + } + // Circle + else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { + anAttrList.push_back(SketchPlugin_Circle::CENTER_ID()); + anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID()); + } + // Arc + else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { + anAttrList.push_back(SketchPlugin_Arc::CENTER_ID()); + anAttrList.push_back(SketchPlugin_Arc::START_ID()); + anAttrList.push_back(SketchPlugin_Arc::END_ID()); } /// \todo Other types of features should be implemented // Check changing of feature's attributes (go through the groups and search usage of the attributes) std::vector::const_iterator anAttrIter; - for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) - { + for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) { std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - { - boost::shared_ptr anAttribute = - boost::dynamic_pointer_cast(theFeature->data()->attribute(*anAttrIter)); + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { + if ((*aGroupIter)->isEmpty()) + continue; + std::shared_ptr anAttribute = std::dynamic_pointer_cast< + ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter)); (*aGroupIter)->updateEntityIfPossible(anAttribute); } } -} + std::vector::iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) + if (!(*aGroupIter)->isEmpty()) + (*aGroupIter)->updateRelatedConstraints(theFeature); +} +// ============================================================================ +// Function: findGroups +// Class: SketchSolver_Session +// Purpose: search groups of entities interacting with given feature +// ============================================================================ void SketchSolver_ConstraintManager::findGroups( - boost::shared_ptr theConstraint, - std::vector& theGroupIDs) const + std::shared_ptr theFeature, + std::set& theGroupIDs) const { - boost::shared_ptr aWP = findWorkplaneForConstraint(theConstraint); + std::shared_ptr aWP = findWorkplane(theFeature); + SketchSolver_ConstraintGroup* 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(theConstraint)) - theGroupIDs.push_back((*aGroupIter)->getId()); + if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { + if (!(*aGroupIter)->isEmpty()) + theGroupIDs.insert((*aGroupIter)->getId()); + else if (!anEmptyGroup) + anEmptyGroup = *aGroupIter; + } + + // When only empty group is found, use it + if (anEmptyGroup && theGroupIDs.empty()) + theGroupIDs.insert(anEmptyGroup->getId()); } -boost::shared_ptr SketchSolver_ConstraintManager::findWorkplaneForConstraint( - boost::shared_ptr theConstraint) const +// ============================================================================ +// Function: findWorkplane +// Class: SketchSolver_Session +// Purpose: search workplane containing given feature +// ============================================================================ +std::shared_ptr SketchSolver_ConstraintManager::findWorkplane( + std::shared_ptr theFeature) const { + // Already verified workplanes + std::set > aVerified; + std::vector::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - { - boost::shared_ptr aWP = (*aGroupIter)->getWorkplane(); - boost::shared_ptr aWPFeatures = - boost::dynamic_pointer_cast(aWP->data()->attribute(SKETCH_ATTR_FEATURES)); - std::list< boost::shared_ptr > aFeaturesList = aWPFeatures->list(); - std::list< boost::shared_ptr >::const_iterator anIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { + std::shared_ptr aWP = (*aGroupIter)->getWorkplane(); + if (aVerified.find(aWP) != aVerified.end()) + continue; + + std::shared_ptr aWPFeatures = std::dynamic_pointer_cast< + ModelAPI_AttributeRefList>(aWP->data()->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 == theConstraint) - return aWP; // workplane is found + if (*anIter == theFeature) + return aWP; // workplane is found + aVerified.insert(aWP); } - return boost::shared_ptr(); + return std::shared_ptr(); } +// ============================================================================ +// Function: resolveConstraints +// Class: SketchSolver_Session +// Purpose: change entities according to available constraints +// ============================================================================ void SketchSolver_ConstraintManager::resolveConstraints() { - std::vector::iterator aGroupIter; + myIsComputed = true; + bool needToUpdate = false; + std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - (*aGroupIter)->resolveConstraints(); -} - - - -// ======================================================== -// ========= SketchSolver_ConstraintGroup =============== -// ======================================================== - -SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup:: - SketchSolver_ConstraintGroup(boost::shared_ptr theWorkplane) - : myID(++myGroupIndexer), - myParamMaxID(0), - myEntityMaxID(0), - myConstrMaxID(0), - myConstraintMap(), - myNeedToSolve(false), - myConstrSolver() -{ - myParams.clear(); - myEntities.clear(); - myConstraints.clear(); - - // Initialize workplane - myWorkplane.h = SLVS_E_UNKNOWN; - addWorkplane(theWorkplane); -} - -SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup() -{ - myParams.clear(); - myEntities.clear(); - myConstraints.clear(); - myConstraintMap.clear(); - - // If the group with maximal identifier is deleted, decrease the indexer - if (myID == myGroupIndexer) - myGroupIndexer--; -} - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane( - boost::shared_ptr theWorkplane) const -{ - return theWorkplane == mySketch; -} - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract( - boost::shared_ptr theConstraint) const -{ - // Check the group is empty - if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty()) - return true; - - /// \todo Should be implemented - return false; -} - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstraint( - boost::shared_ptr theConstraint) -{ - // There is no workplane yet, something wrong - if (myWorkplane.h == SLVS_E_UNKNOWN) - return false; - - // Search this constraint in the current group to update it - std::map, Slvs_hConstraint>::const_iterator - aConstrMapIter = myConstraintMap.find(theConstraint); - std::vector::iterator aConstrIter; - if (aConstrMapIter != myConstraintMap.end()) - { - int aConstrPos = Search(aConstrMapIter->second, myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - } - - // Get constraint type and verify the constraint parameters are correct - int aConstrType = getConstraintType(theConstraint); - if (aConstrType == SLVS_C_UNKNOWN || - (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) - return false; - - // Create constraint parameters - double aDistance = 0.0; // scalar value of the constraint - boost::shared_ptr aDistAttr = - boost::dynamic_pointer_cast(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE)); - if (aDistAttr) - { - aDistance = aDistAttr->value(); - if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance) - { - myNeedToSolve = true; - aConstrIter->valA = aDistance; - } - } - - Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) - { - aConstrEnt[indAttr] = SLVS_E_UNKNOWN; - boost::shared_ptr aConstrAttr = - boost::dynamic_pointer_cast( - theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr]) - ); - if (!aConstrAttr) continue; - aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); - } - - if (aConstrMapIter == myConstraintMap.end()) - { - // Create SolveSpace constraint structure - Slvs_Constraint aConstraint = - Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, - aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]); - myConstraints.push_back(aConstraint); - myConstraintMap[theConstraint] = aConstraint.h; - } - return true; -} - -Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeEntity( - boost::shared_ptr theEntity) -{ - // If the entity is already in the group, try to find it - std::map, Slvs_hEntity>::const_iterator - aEntIter = myEntityMap.find(theEntity); - std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise - if (aEntIter == myEntityMap.end()) // no such entity => should be created - aParamIter = myParams.end(); - else - { // the entity already exists - int aEntPos = Search(aEntIter->second, myEntities); - int aParamPos = Search(myEntities[aEntPos].param[0], myParams); - aParamIter = myParams.begin() + aParamPos; - } - - // Look over supported types of entities - - // Point in 3D - boost::shared_ptr aPoint = - boost::dynamic_pointer_cast(theEntity); - if (aPoint) - { - Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter); - Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter); - Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter); - - if (aEntIter != myEntityMap.end()) // the entity already exists - return aEntIter->second; - - // New entity - Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); - myEntities.push_back(aPtEntity); - myEntityMap[theEntity] = aPtEntity.h; - return aPtEntity.h; - } - - // Point in 2D - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(theEntity); - if (aPoint2D) - { - // The 2D points are created on workplane. So, if there is no workplane yet, then error - if (myWorkplane.h == SLVS_E_UNKNOWN) - return SLVS_E_UNKNOWN; - Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); - Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); - - if (aEntIter != myEntityMap.end()) // the entity already exists - return aEntIter->second; - - // New entity - Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); - myEntities.push_back(aPt2DEntity); - myEntityMap[theEntity] = aPt2DEntity.h; - return aPt2DEntity.h; - } - - /// \todo Other types of entities - - // Unsupported or wrong entity type - return SLVS_E_UNKNOWN; -} - -Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeNormal( - boost::shared_ptr theDirX, - boost::shared_ptr theDirY, - boost::shared_ptr theNorm) -{ - boost::shared_ptr aDirX = - boost::dynamic_pointer_cast(theDirX); - boost::shared_ptr aDirY = - boost::dynamic_pointer_cast(theDirY); - if (!aDirX || !aDirY || - (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || - (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance)) - return SLVS_E_UNKNOWN; - - // quaternion parameters of normal vector - double qw, qx, qy, qz; - Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), - aDirY->x(), aDirY->y(), aDirY->z(), - &qw, &qx, &qy, &qz); - double aNormCoord[4] = {qw, qx, qy, qz}; - - // Try to find existent normal - std::map, Slvs_hEntity>::const_iterator - aEntIter = myEntityMap.find(theNorm); - std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise - if (aEntIter == myEntityMap.end()) // no such entity => should be created - aParamIter = myParams.end(); - else - { // the entity already exists, update it - int aEntPos = Search(aEntIter->second, myEntities); - int aParamPos = Search(myEntities[aEntPos].param[0], myParams); - aParamIter = myParams.begin() + aParamPos; - } - - // Change parameters of the normal - Slvs_hParam aNormParams[4]; - for (int i = 0; i < 4; i++) - aNormParams[i] = changeParameter(aNormCoord[i], aParamIter); - - if (aEntIter != myEntityMap.end()) // the entity already exists - return aEntIter->second; - - // Create a normal - Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, - aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]); - myEntities.push_back(aNormal); - myEntityMap[theNorm] = aNormal.h; - return aNormal.h; -} - - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane( - boost::shared_ptr theSketch) -{ - if (myWorkplane.h) - return false; // the workplane already exists - - mySketch = theSketch; - return updateWorkplane(); -} - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane() -{ - // Get parameters of workplane - boost::shared_ptr aDirX = mySketch->data()->attribute(SKETCH_ATTR_DIRX); - boost::shared_ptr aDirY = mySketch->data()->attribute(SKETCH_ATTR_DIRY); - boost::shared_ptr aNorm = mySketch->data()->attribute(SKETCH_ATTR_NORM); - boost::shared_ptr anOrigin = mySketch->data()->attribute(SKETCH_ATTR_ORIGIN); - // Transform them into SolveSpace format - Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm); - if (!aNormalWP) return false; - Slvs_hEntity anOriginWP = changeEntity(anOrigin); - if (!anOriginWP) return false; - - if (!myWorkplane.h) - { - // Create workplane - myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP); - // Workplane should be added to the list of entities - myEntities.push_back(myWorkplane); - } - return true; -} - - -Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeParameter( - const double& theParam, - std::vector::const_iterator& thePrmIter) -{ - if (thePrmIter != myParams.end()) - { // Parameter should be updated - int aParamPos = thePrmIter - myParams.begin(); - if (fabs(thePrmIter->val - theParam) > tolerance) - { - myNeedToSolve = true; // parameter is changed, need to resolve constraints - myParams[aParamPos].val = theParam; - } - thePrmIter++; - return myParams[aParamPos].h; - } - - // Newly created parameter - Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam); - myParams.push_back(aParam); - myNeedToSolve = true; - // The list of parameters is changed, move iterator to the end of the list to avoid problems - thePrmIter = myParams.end(); - return aParam.h; -} - -int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType( - const boost::shared_ptr& theConstraint) const -{ - // Constraint for coincidence of two points - boost::shared_ptr aPtEquiv = - boost::dynamic_pointer_cast(theConstraint); - if (aPtEquiv) - { - // Verify the constraint has only two attributes and they are points - int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point - int aPt3d = 0; // bit-mapped field, the same information for 3D points - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) - { - boost::shared_ptr anAttr = - boost::dynamic_pointer_cast( - theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr]) - ); - if (!anAttr) continue; - // Verify the attribute is a 2D point - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(anAttr->attr()); - if (aPoint2D) - { - aPt2d |= (1 << indAttr); - continue; - } - // Verify the attribute is a 3D point - boost::shared_ptr aPoint3D = - boost::dynamic_pointer_cast(anAttr->attr()); - if (aPoint3D) - { - aPt3d |= (1 << indAttr); - continue; - } - // Attribute neither 2D nor 3D point is not supported by this type of constraint - return SLVS_C_UNKNOWN; - } - // The constrained points should be in first and second positions, - // so the expected value of aPt2d or aPt3d is 3 - if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3)) - return SLVS_C_POINTS_COINCIDENT; - // Constraint parameters are wrong - return SLVS_C_UNKNOWN; - } - - /// \todo Implement other kind of constrtaints - - return SLVS_C_UNKNOWN; -} - -void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::resolveConstraints() -{ - if (!myNeedToSolve) - return; + if ((*aGroupIter)->resolveConstraints()) + needToUpdate = true; - myConstrSolver.setGroupID(myID); - myConstrSolver.setParameters(myParams); - myConstrSolver.setEntities(myEntities); - myConstrSolver.setConstraints(myConstraints); - - if (myConstrSolver.solve() == SLVS_RESULT_OKAY) - { // solution succeeded, store results into correspondent attributes - // Obtain result into the same list of parameters - if (!myConstrSolver.getResult(myParams)) - return; - - std::map, Slvs_hEntity>::iterator - anEntIter = myEntityMap.begin(); - for ( ; anEntIter != myEntityMap.end(); anEntIter++) - updateAttribute(anEntIter->first, anEntIter->second); - } - /// \todo Implement error handling - - removeTemporaryConstraints(); - myNeedToSolve = false; -} - -bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateGroup() -{ - // Check for valid sketch - if (!mySketch->data()->isValid()) - return true; - - // Fast check for constraint validity. If all constraints are valid, no need to update the group - std::map, Slvs_hConstraint>::reverse_iterator - aConstrIter = myConstraintMap.rbegin(); - bool isAllValid = true; - for ( ; isAllValid && aConstrIter != myConstraintMap.rend(); aConstrIter++) - if (!aConstrIter->first->data()->isValid()) - isAllValid = false; - if (isAllValid) - return false; - - // Remove invalid constraints. - // There only constraint will be deleted (parameters and entities) will be removed below - std::list< boost::shared_ptr > aConstrToDelete; - std::map anEntToDelete; // entities will be removed if no valid constraints use them - for (aConstrIter = myConstraintMap.rbegin(); aConstrIter != myConstraintMap.rend(); aConstrIter++) - { - bool isValid = aConstrIter->first->data()->isValid(); - - int aConstrPos = Search(aConstrIter->second, myConstraints); - if (aConstrPos < (int)myConstraints.size()) - { - Slvs_hEntity aConstrEnt[] = { - myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, - myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB}; - for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != SLVS_E_UNKNOWN) - { - if (anEntToDelete.find(aConstrEnt[i]) == anEntToDelete.end()) - anEntToDelete[aConstrEnt[i]] = !isValid; - else if (isValid) // constraint is valid => no need to remove its entities - anEntToDelete[aConstrEnt[i]] = false; - } - if (!isValid) - { - myConstraints.erase(myConstraints.begin() + aConstrPos); - if (aConstrIter->second == myConstrMaxID) // When the constraint with highest ID is removed, decrease indexer - myConstrMaxID--; - aConstrToDelete.push_front(aConstrIter->first); - } - } - } - std::list< boost::shared_ptr >::iterator aDelIter; - for (aDelIter = aConstrToDelete.begin(); aDelIter != aConstrToDelete.end(); aDelIter++) - myConstraintMap.erase(*aDelIter); - - // Remove invalid and unused entities - std::map::reverse_iterator aEDelIter; - for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++) - if (aEDelIter->second) - { - int anEntPos = Search(aEDelIter->first, myEntities); - std::vector::iterator aEntIter = myEntities.begin() + anEntPos; - // Number of parameters for the entity - int aNbParams = 0; - while (aEntIter->param[aNbParams]) aNbParams++; - if (aNbParams == 0) continue; - // Decrease parameter indexer if there are deleted parameter with higher IDs - if (aEntIter->param[aNbParams-1] == myParamMaxID) - myParamMaxID -= aNbParams; - // Remove parameters of the entity - int aParamPos = Search(aEntIter->param[0], myParams); - myParams.erase(myParams.begin() + aParamPos, - myParams.begin() + aParamPos + aNbParams); - - // Remove entity - if (aEDelIter->first == myEntityMaxID) - myEntityMaxID--; - myEntities.erase(myEntities.begin() + anEntPos); - // Remove such entity from myEntityMap - std::map, Slvs_hEntity>::iterator - anEntMapIter = myEntityMap.begin(); - for ( ; anEntMapIter != myEntityMap.end(); anEntMapIter++) - if (anEntMapIter->second == aEDelIter->first) - break; - if (anEntMapIter != myEntityMap.end()) - myEntityMap.erase(anEntMapIter); - } - - return false; -} - -void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateAttribute( - boost::shared_ptr theAttribute, - const Slvs_hEntity& theEntityID) -{ - // Search the position of the first parameter of the entity - int anEntPos = Search(theEntityID, myEntities); - int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams); - - // Look over supported types of entities - - // Point in 3D - boost::shared_ptr aPoint = - boost::dynamic_pointer_cast(theAttribute); - if (aPoint) - { - aPoint->setValue(myParams[aFirstParamPos].val, - myParams[aFirstParamPos+1].val, - myParams[aFirstParamPos+2].val); - return ; - } - - // Point in 2D - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(theAttribute); - if (aPoint2D) - { - aPoint2D->setValue(myParams[aFirstParamPos].val, - myParams[aFirstParamPos+1].val); - return ; - } - - /// \todo Support other types of entities + // Features may be updated => send events + if (needToUpdate) + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + myIsComputed = false; } -void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateEntityIfPossible( - boost::shared_ptr theEntity) -{ - if (myEntityMap.find(theEntity) != myEntityMap.end()) - { - // If the attribute is a point and it is changed (the group needs to rebuild), - // probably user has dragged this point into this position, - // so it is necessary to add constraint which will quarantee the point will not change - - // Store myNeedToSolve flag to verify the entity is really changed - bool aNeedToSolveCopy = myNeedToSolve; - myNeedToSolve = false; - - changeEntity(theEntity); - - if (myNeedToSolve) // the entity is changed - { - // Verify the entity is a point and add temporary constraint of permanency - boost::shared_ptr aPoint = - boost::dynamic_pointer_cast(theEntity); - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(theEntity); - if (aPoint || aPoint2D) - addTemporaryConstraintWhereDragged(theEntity); - } - - // Restore flag of changes - myNeedToSolve = myNeedToSolve || aNeedToSolveCopy; - } -} - -void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged( - boost::shared_ptr theEntity) -{ - // Find identifier of the entity - std::map, Slvs_hEntity>::const_iterator - anEntIter = myEntityMap.find(theEntity); - - // Create WHERE_DRAGGED constraint - Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, - myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0); - myConstraints.push_back(aWDConstr); - myTempConstraints.push_back(aWDConstr.h); -} - -void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::removeTemporaryConstraints() -{ - std::list::reverse_iterator aTmpConstrIter; - for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++) - { - int aConstrPos = Search(*aTmpConstrIter, myConstraints); - myConstraints.erase(myConstraints.begin() + aConstrPos); - - // If the removing constraint has higher index, decrease the indexer - if (*aTmpConstrIter == myConstrMaxID) - myConstrMaxID--; - } - myTempConstraints.clear(); -} - - - -// ======================================================== -// ========= Auxiliary functions =============== -// ======================================================== - -template -int Search(const uint32_t& theEntityID, const std::vector& theEntities) -{ - int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0; - int aVecSize = theEntities.size(); - while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) - aResIndex--; - while (aResIndex < aVecSize && theEntities[aResIndex].h < theEntityID) - aResIndex++; - if (aResIndex == -1) - aResIndex = aVecSize; - return aResIndex; -}