X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintGroup.cpp;h=f311546396df5e0c87daf3ab05c3ab0fad49e324;hb=2d309adb3c465a840e8f5ceeba28ec145e5a45a2;hp=186e80505628cc859a2da9867c6558333338a0b2;hpb=f581964034f8df715c46a07c5ecb762492d6b4cf;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index 186e80505..f31154639 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -1,3 +1,5 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + // File: SketchSolver_ConstraintGroup.cpp // Created: 27 May 2014 // Author: Artem ZHIDKOV @@ -6,17 +8,23 @@ #include +#include #include +#include +#include #include #include #include #include #include -#include +#include +#include +#include #include #include #include +#include #include #include @@ -30,6 +38,22 @@ /// Tolerance for value of parameters const double tolerance = 1.e-10; +/* + * Collects all sketch solver error' codes + * as inline static functions + * TODO: Move this class into a separate file + */ +class SketchSolver_Error +{ + public: + /// The value parameter for the constraint + inline static const std::string& CONSTRAINTS() + { + static const std::string MY_ERROR_VALUE("Conflicting constraints"); + return MY_ERROR_VALUE; + } +}; + /// This value is used to give unique index to the groups static Slvs_hGroup myGroupIndexer = 0; @@ -38,28 +62,28 @@ static Slvs_hGroup myGroupIndexer = 0; * \param[in] theEntities list of elements * \return position of the found element or -1 if the element is not found */ -template +template static int Search(const uint32_t& theEntityID, const std::vector& theEntities); - // ======================================================== // ========= SketchSolver_ConstraintGroup =============== // ======================================================== -SketchSolver_ConstraintGroup:: - SketchSolver_ConstraintGroup(boost::shared_ptr theWorkplane) - : myID(++myGroupIndexer), - myParamMaxID(0), - myEntityMaxID(0), - myConstrMaxID(0), - myConstraintMap(), - myNeedToSolve(false), - myConstrSolver() +SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup( + std::shared_ptr theWorkplane) + : myID(++myGroupIndexer), + myParamMaxID(0), + myEntityMaxID(0), + myConstrMaxID(0), + myConstraintMap(), + myNeedToSolve(false), + myConstrSolver() { myParams.clear(); myEntities.clear(); + myEntOfConstr.clear(); myConstraints.clear(); - + myTempConstraints.clear(); myTempPointWhereDragged.clear(); myTempPointWDrgdID = 0; @@ -77,6 +101,7 @@ SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup() { myParams.clear(); myEntities.clear(); + myEntOfConstr.clear(); myConstraints.clear(); myConstraintMap.clear(); myTempConstraints.clear(); @@ -93,7 +118,7 @@ SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup() // Purpose: verify the group is based on the given workplane // ============================================================================ bool SketchSolver_ConstraintGroup::isBaseWorkplane( - boost::shared_ptr theWorkplane) const + std::shared_ptr theWorkplane) const { return theWorkplane == mySketch; } @@ -104,120 +129,413 @@ bool SketchSolver_ConstraintGroup::isBaseWorkplane( // Purpose: verify are there any entities in the group used by given constraint // ============================================================================ bool SketchSolver_ConstraintGroup::isInteract( - boost::shared_ptr theConstraint) const + std::shared_ptr theFeature) const { // Check the group is empty - if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty()) + if (isEmpty()) return true; - // Go through constraint entities and verify if some of them already in the group - for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++) - { - boost::shared_ptr aCAttrRef = - boost::dynamic_pointer_cast( - theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i]) - ); - if (!aCAttrRef) continue; - if (!aCAttrRef->isFeature() && - myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end()) - return true; - if (aCAttrRef->isFeature() && - myEntityFeatMap.find(aCAttrRef->feature()) != myEntityFeatMap.end()) - return true; + // Check if the feature is already in the group + if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end()) + return true; + std::shared_ptr aConstr = + std::dynamic_pointer_cast(theFeature); + if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end()) + return true; + + // Go through the attributes and verify if some of them already in the group + std::list> + anAttrList = theFeature->data()->attributes(std::string()); + std::list>::const_iterator + anAttrIter = anAttrList.begin(); + for ( ; anAttrIter != anAttrList.end(); anAttrIter++) { + std::shared_ptr aCAttrRef = + std::dynamic_pointer_cast(*anAttrIter); + if (!aCAttrRef || !aCAttrRef->isObject()) { + std::shared_ptr anAttr = + aCAttrRef ? aCAttrRef->attr() : *anAttrIter; + if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end()) + return true; + } else { + ResultConstructionPtr aRC = std::dynamic_pointer_cast( + aCAttrRef->object()); + if (!aRC) + continue; + std::shared_ptr aDoc = aRC->document(); + FeaturePtr aFeature = aDoc->feature(aRC); + if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end()) + return true; + // search attributes of a feature to be parameters of constraint + std::list > aFeatAttrList = + aFeature->data()->attributes(std::string()); + std::list >::const_iterator aFAIter = aFeatAttrList + .begin(); + for (; aFAIter != aFeatAttrList.end(); aFAIter++) + if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end()) + return true; + } } // Entities did not found return false; } +// ============================================================================ +// Function: checkConstraintConsistence +// Class: SketchSolver_ConstraintGroup +// Purpose: verifies and changes parameters of the constraint +// ============================================================================ +void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint) +{ + if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) { + // Get constraint parameters and check the sign of constraint value + + // point coordinates + int aPtPos = Search(theConstraint.ptA, myEntities); + int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); + std::shared_ptr aPoint( + new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); + + // line coordinates + int aLnPos = Search(theConstraint.entityA, myEntities); + aPtPos = Search(myEntities[aLnPos].point[0], myEntities); + aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); + std::shared_ptr aStart( + new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val)); + aPtPos = Search(myEntities[aLnPos].point[1], myEntities); + aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); + std::shared_ptr aEnd( + new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); + + aEnd = aEnd->added(aStart); + aPoint = aPoint->added(aStart); + if (aPoint->cross(aEnd) * theConstraint.valA < 0.0) + theConstraint.valA *= -1.0; + } +} + // ============================================================================ // Function: changeConstraint // Class: SketchSolver_ConstraintGroup // Purpose: create/update the constraint in the group // ============================================================================ bool SketchSolver_ConstraintGroup::changeConstraint( - boost::shared_ptr theConstraint) + std::shared_ptr theConstraint) { // There is no workplane yet, something wrong if (myWorkplane.h == SLVS_E_UNKNOWN) return false; + if (theConstraint && theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) + return changeRigidConstraint(theConstraint); + // Search this constraint in the current group to update it - std::map, Slvs_hConstraint>::const_iterator - aConstrMapIter = myConstraintMap.find(theConstraint); + ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); std::vector::iterator aConstrIter; - if (aConstrMapIter != myConstraintMap.end()) - { - int aConstrPos = Search(aConstrMapIter->second, myConstraints); + if (aConstrMapIter != myConstraintMap.end()) { + int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); aConstrIter = myConstraints.begin() + aConstrPos; } // Get constraint type and verify the constraint parameters are correct SketchSolver_Constraint aConstraint(theConstraint); int aConstrType = aConstraint.getType(); - if (aConstrType == SLVS_C_UNKNOWN || - (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) + if (aConstrType == SLVS_C_UNKNOWN + || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) return false; const std::vector& aConstraintAttributes = aConstraint.getAttributes(); // 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) - { + double aDistance = 0.0; // scalar value of the constraint + AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast( + theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE())); + if (aDistAttr) { aDistance = aDistAttr->value(); - if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance) - { - myNeedToSolve = true; - aConstrIter->valA = aDistance; - } + // Issue #196: checking the positivity of the distance constraint + if (aDistance < tolerance && + (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE)) + return false; // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter if (aConstrType == SLVS_C_DIAMETER) aDistance *= 2.0; + 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++) - { + size_t aNbTmpConstraints = myTempConstraints.size(); + 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(aConstraintAttributes[indAttr]) - ); - if (!aConstrAttr) continue; + std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>( + theConstraint->data()->attribute(aConstraintAttributes[indAttr])); + if (!aConstrAttr) + continue; - // For the length constraint the start and end points of the line should be added to the entities list instead of line - if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare(SKETCH_CONSTRAINT_LENGTH_KIND) == 0) - { - boost::shared_ptr aData = aConstrAttr->feature()->data(); - aConstrEnt[indAttr] = changeEntity(aData->attribute(LINE_ATTR_START)); - aConstrEnt[indAttr+1] = changeEntity(aData->attribute(LINE_ATTR_END)); - break; // there should be no other entities + // Convert the object of the attribute to the feature + FeaturePtr aFeature; + if (aConstrAttr->isObject() && aConstrAttr->object()) { + ResultConstructionPtr aRC = std::dynamic_pointer_cast( + aConstrAttr->object()); + if (!aRC) + continue; + std::shared_ptr aDoc = aRC->document(); + aFeature = aDoc->feature(aRC); } - else if (aConstrAttr->isFeature()) - aConstrEnt[indAttr] = changeEntity(aConstrAttr->feature()); + + // For the length constraint the start and end points of the line should be added to the entities list instead of line + if (aConstrType == SLVS_C_PT_PT_DISTANCE + && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) { + Slvs_hEntity aLineEnt = changeEntityFeature(aFeature); + int aEntPos = Search(aLineEnt, myEntities); + aConstrEnt[indAttr++] = myEntities[aEntPos].point[0]; + aConstrEnt[indAttr++] = myEntities[aEntPos].point[1]; + while (indAttr < CONSTRAINT_ATTR_SIZE) + aConstrEnt[indAttr++] = 0; + break; // there should be no other entities + } else if (aConstrAttr->isObject()) + aConstrEnt[indAttr] = changeEntityFeature(aFeature); else aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); } - if (aConstrMapIter == myConstraintMap.end()) - { + if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint // Several points may be coincident, it is not necessary to store all constraints between them. // Try to find sequence of coincident points which connects the points of new constraint - if (aConstrType == SLVS_C_POINTS_COINCIDENT && - !addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) - { - myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes - return false; + if (aConstrType == SLVS_C_POINTS_COINCIDENT) { + if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence + return false; + if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) { + myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes + return false; + } + if (aNbTmpConstraints < myTempConstraints.size()) { + // There was added temporary constraint. Check that there is no coincident points which already rigid. + + // Get list of already fixed points + std::set anAlreadyFixed; + std::vector::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); aCIter++) + if (aCIter->type == SLVS_C_WHERE_DRAGGED) { + std::list::const_iterator aTmpIt = myTempConstraints.begin(); + for (; aTmpIt != myTempConstraints.end(); aTmpIt++) + if (*aTmpIt == aCIter->h) + break; + if (aTmpIt == myTempConstraints.end()) + anAlreadyFixed.insert(aCIter->ptA); + } + + std::set aTmpConstrToDelete; + std::list::reverse_iterator aTmpIter = myTempConstraints.rbegin(); + size_t aCurSize = myTempConstraints.size(); + for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend(); + aTmpIter++, aCurSize--) { + int aConstrPos = Search(*aTmpIter, myConstraints); + std::vector >::const_iterator + aCoincIter = myCoincidentPoints.begin(); + for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) + if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) { + std::set::const_iterator anIt; + for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++) + if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) { + aTmpConstrToDelete.insert(*aTmpIter); + break; + } + break; + } + } + if (!aTmpConstrToDelete.empty()) + removeTemporaryConstraints(aTmpConstrToDelete); + } } // Create SolveSpace constraint structure - Slvs_Constraint aConstraint = - Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, - aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]); + 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; + myConstraintMap[theConstraint] = std::vector(1, aConstraint.h); + int aConstrPos = Search(aConstraint.h, myConstraints); + aConstrIter = myConstraints.begin() + aConstrPos; + myNeedToSolve = true; + } else { // Attributes of constraint may be changed => update constraint + Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB, + &aConstrIter->entityA, &aConstrIter->entityB, + &aConstrIter->entityC, &aConstrIter->entityD}; + for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { + if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr]) + { + *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr]; + myNeedToSolve = true; + } + } + } + + // Update flags of entities to be used by constraints + for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) + if (aConstrEnt[indAttr] != 0) { + int aPos = Search(aConstrEnt[indAttr], myEntities); + myEntOfConstr[aPos] = true; + // Sub-entities should be used implcitly + Slvs_hEntity* aEntPtr = myEntities[aPos].point; + while (*aEntPtr != 0) { + aPos = Search(*aEntPtr, myEntities); + myEntOfConstr[aPos] = true; + aEntPtr++; + } + } + + checkConstraintConsistence(*aConstrIter); + return true; +} + +// ============================================================================ +// Function: changeRigidConstraint +// Class: SketchSolver_ConstraintGroup +// Purpose: create/update the "Rigid" constraint in the group +// ============================================================================ +bool SketchSolver_ConstraintGroup::changeRigidConstraint( + std::shared_ptr theConstraint) +{ + // Search this constraint in the current group to update it + ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); + std::vector::iterator aConstrIter; + if (aConstrMapIter != myConstraintMap.end()) { + int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); + aConstrIter = myConstraints.begin() + aConstrPos; + } + + // Get constraint type and verify the constraint parameters are correct + SketchSolver_Constraint aConstraint(theConstraint); + int aConstrType = aConstraint.getType(); + if (aConstrType == SLVS_C_UNKNOWN + || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) + return false; + const std::vector& aConstraintAttributes = aConstraint.getAttributes(); + + Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN; + std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>( + theConstraint->data()->attribute(aConstraintAttributes[0])); + if (!aConstrAttr) + return false; + + // Convert the object of the attribute to the feature + FeaturePtr aFeature; + if (aConstrAttr->isObject() && aConstrAttr->object()) { + ResultConstructionPtr aRC = std::dynamic_pointer_cast( + aConstrAttr->object()); + if (!aRC) + return false; + std::shared_ptr aDoc = aRC->document(); + aFeature = aDoc->feature(aRC); + } + + aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr()); + + if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint + // Check the fixed entity is not a point. + std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0])); + std::shared_ptr aPoint = + std::dynamic_pointer_cast(aConstrAttr->attr()); + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(aConstrAttr->attr()); + if (aPoint || aPoint2D) { + // Create SolveSpace constraint structure + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, + aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint] = std::vector(1, aConstraint.h); + int aConstrPos = Search(aConstraint.h, myConstraints); + aConstrIter = myConstraints.begin() + aConstrPos; + myNeedToSolve = true; + } else { + myConstraintMap[theConstraint] = std::vector(); + + // To avoid SolveSpace problems: + // * if the circle is rigid, we will fix its center and radius; + // * if the arc is rigid, we will fix its start and end points and radius. + double aRadius = 0.0; + bool isArc = false; + bool isCircle = false; + if (aFeature) { + if (aFeature->getKind() == SketchPlugin_Arc::ID()) { + std::shared_ptr aCenter = + std::dynamic_pointer_cast( + aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID())); + std::shared_ptr aStart = + std::dynamic_pointer_cast( + aFeature->data()->attribute(SketchPlugin_Arc::START_ID())); + aRadius = aStart->pnt()->distance(aCenter->pnt()); + isArc = true; + } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) { + aRadius = std::dynamic_pointer_cast( + aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value(); + isCircle = true; + } + } + + // Get list of already fixed points + std::set anAlreadyFixed; + std::vector::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); aCIter++) + if (aCIter->type == SLVS_C_WHERE_DRAGGED) + anAlreadyFixed.insert(aCIter->ptA); + + // Create constraints to fix the parameters of the entity + int aEntPos = Search(aConstrEnt, myEntities); + Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point; + if (isArc) aPointsPtr++; // avoid to fix center of arc + while (*aPointsPtr != 0) { + // Avoid to create additional "Rigid" constraints for coincident points + bool isCoincAlreadyFixed = false; + if (!anAlreadyFixed.empty()) { + if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end()) + isCoincAlreadyFixed = true; + + std::vector >::const_iterator aCoincIter = + myCoincidentPoints.begin(); + for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) { + if (aCoincIter->find(*aPointsPtr) == aCoincIter->end()) + continue; + std::set::const_iterator anIter = anAlreadyFixed.begin(); + for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++) + if (aCoincIter->find(*anIter) != aCoincIter->end()) + isCoincAlreadyFixed = true; + } + } + + if (!isCoincAlreadyFixed) { + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, + *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + } + aPointsPtr++; + } + + if (isArc || isCircle) { // add radius constraint + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + } + + // The object is already rigid, so there is no constraints added + if (myConstraintMap[theConstraint].empty()) { + myConstraintMap.erase(theConstraint); + myNeedToSolve = false; + } + else + myNeedToSolve = true; + } } return true; } @@ -228,173 +546,200 @@ bool SketchSolver_ConstraintGroup::changeConstraint( // Purpose: create/update the element affected by any constraint // ============================================================================ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( - boost::shared_ptr theEntity) + std::shared_ptr theEntity) { // If the entity is already in the group, try to find it - std::map, Slvs_hEntity>::const_iterator - aEntIter = myEntityAttrMap.find(theEntity); - std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise - if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created + std::map, Slvs_hEntity>::const_iterator aEntIter = + myEntityAttrMap.find(theEntity); + int aEntPos; + std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise + if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created aParamIter = myParams.end(); - else - { // the entity already exists - int aEntPos = Search(aEntIter->second, myEntities); + else { // the entity already exists + aEntPos = Search(aEntIter->second, myEntities); int aParamPos = Search(myEntities[aEntPos].param[0], myParams); aParamIter = myParams.begin() + aParamPos; } - const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists + const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists + const bool isNeedToSolve = myNeedToSolve; + myNeedToSolve = false; + + if (isEntExists) { + // Verify that the entity is not used by "Rigid" constraint. + // If it is used, the object should not move. + std::vector >::iterator aCoincIter = myCoincidentPoints.begin(); + for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) + if (aCoincIter->find(aEntIter->second) != aCoincIter->end()) + break; + std::set aCoincident; + if (aCoincIter != myCoincidentPoints.end()) { + aCoincident = *aCoincIter; + aCoincident.erase(aEntIter->second); + + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && + aCoincident.find(aConstrIter->ptA) != aCoincident.end()) { + myNeedToSolve = true; + return aEntIter->second; + } + } + } // Look over supported types of entities + Slvs_Entity aNewEntity; + aNewEntity.h = SLVS_E_UNKNOWN; // Point in 3D - boost::shared_ptr aPoint = - boost::dynamic_pointer_cast(theEntity); - if (aPoint) - { + std::shared_ptr aPoint = std::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 (isEntExists) - return aEntIter->second; - - // New entity - Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); - myEntities.push_back(aPtEntity); - myEntityAttrMap[theEntity] = aPtEntity.h; - return aPtEntity.h; - } - - // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error - if (myWorkplane.h == SLVS_E_UNKNOWN) - return SLVS_E_UNKNOWN; - - // Point in 2D - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(theEntity); - if (aPoint2D) - { - Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); - Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); - - if (isEntExists) - return aEntIter->second; - - // New entity - Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); - myEntities.push_back(aPt2DEntity); - myEntityAttrMap[theEntity] = aPt2DEntity.h; - return aPt2DEntity.h; + if (!isEntExists) // New entity + aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); + } else { + // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error + if (myWorkplane.h == SLVS_E_UNKNOWN) + return SLVS_E_UNKNOWN; + + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theEntity); + if (aPoint2D) { + Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); + Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); + if (!isEntExists) // New entity + aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); + if (aScalar) { + Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter); + if (!isEntExists) // New entity + aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue); + } + } } + /// \todo Other types of entities - // Scalar value (used for the distance entities) - boost::shared_ptr aScalar = - boost::dynamic_pointer_cast(theEntity); - if (aScalar) - { - Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter); - - if (isEntExists) - return aEntIter->second; + Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type - // New entity - Slvs_Entity aDistance = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue); - myEntities.push_back(aDistance); - myEntityAttrMap[theEntity] = aDistance.h; - return aDistance.h; + if (isEntExists) { + myNeedToSolve = myNeedToSolve || isNeedToSolve; + aResult = aEntIter->second; + } else if (aNewEntity.h != SLVS_E_UNKNOWN) { + myEntities.push_back(aNewEntity); + myEntOfConstr.push_back(false); + myEntityAttrMap[theEntity] = aNewEntity.h; + aResult = aNewEntity.h; } - /// \todo Other types of entities + // If the attribute was changed by the user, we need to fix it before solving + if (myNeedToSolve && theEntity->isImmutable()) + addTemporaryConstraintWhereDragged(theEntity, false); - // Unsupported or wrong entity type - return SLVS_E_UNKNOWN; + return aResult; } - // ============================================================================ // Function: changeEntity // Class: SketchSolver_ConstraintGroup // Purpose: create/update the element defined by the feature affected by any constraint // ============================================================================ -Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( - FeaturePtr theEntity) +Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity) { + if (!theEntity->data()->isValid()) + return SLVS_E_UNKNOWN; // If the entity is already in the group, try to find it - std::map::const_iterator - aEntIter = myEntityFeatMap.find(theEntity); + std::map::const_iterator aEntIter = myEntityFeatMap.find(theEntity); // defines that the entity already exists const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end()); + + Slvs_Entity aNewEntity; + aNewEntity.h = SLVS_E_UNKNOWN; // SketchPlugin features - boost::shared_ptr aFeature; - boost::dynamic_pointer_cast(theEntity); - if (aFeature) - { // Verify the feature by its kind + std::shared_ptr aFeature = std::dynamic_pointer_cast< + SketchPlugin_Feature>(theEntity); + if (aFeature) { // Verify the feature by its kind const std::string& aFeatureKind = aFeature->getKind(); + AttributePtr anAttribute; // Line - if (aFeatureKind.compare(SKETCH_LINE_KIND) == 0) - { - Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(LINE_ATTR_START)); - Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(LINE_ATTR_END)); + if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute); - if (isEntExists) - return aEntIter->second; + anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aEnd = changeEntity(anAttribute); - // New entity - Slvs_Entity aLineEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd); - myEntities.push_back(aLineEntity); - myEntityFeatMap[theEntity] = aLineEntity.h; - return aLineEntity.h; + if (!isEntExists) // New entity + aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd); } // Circle - else if (aFeatureKind.compare(SKETCH_CIRCLE_KIND) == 0) - { - Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_CENTER)); - Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_RADIUS)); - - if (isEntExists) - return aEntIter->second; - - // New entity - Slvs_Entity aCircleEntity = - Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, myWorkplane.normal, aRadius); - myEntities.push_back(aCircleEntity); - myEntityFeatMap[theEntity] = aCircleEntity.h; - return aCircleEntity.h; + else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute); + + anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aRadius = changeEntity(anAttribute); + + if (!isEntExists) // New entity + aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, + myWorkplane.normal, aRadius); } // Arc - else if (aFeatureKind.compare(SKETCH_ARC_KIND) == 0) - { - Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(ARC_ATTR_CENTER)); - Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(ARC_ATTR_START)); - Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(ARC_ATTR_END)); - - if (isEntExists) - return aEntIter->second; - - Slvs_Entity anArcEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, - myWorkplane.h, myWorkplane.normal, aCenter, aStart, aEnd); - myEntities.push_back(anArcEntity); - myEntityFeatMap[theEntity] = anArcEntity.h; - return anArcEntity.h; + else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute); + + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute); + + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aEnd = changeEntity(anAttribute); + + if (!isEntExists) + aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h, + myWorkplane.normal, aCenter, aStart, aEnd); } // Point (it has low probability to be an attribute of constraint, so it is checked at the end) - else if (aFeatureKind.compare(SKETCH_POINT_KIND) == 0) - { - Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(POINT_ATTR_COORD)); + else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aPoint = changeEntity(anAttribute); if (isEntExists) return aEntIter->second; // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier myEntityFeatMap[theEntity] = aPoint; + myNeedToSolve = true; return aPoint; } } - /// \todo Other types of features + if (isEntExists) + return aEntIter->second; + + if (aNewEntity.h != SLVS_E_UNKNOWN) { + myEntities.push_back(aNewEntity); + myEntOfConstr.push_back(false); + myEntityFeatMap[theEntity] = aNewEntity.h; + myNeedToSolve = true; + return aNewEntity.h; + } + // Unsupported or wrong entity type return SLVS_E_UNKNOWN; } @@ -405,34 +750,28 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( // Purpose: create/update the normal of workplane // ============================================================================ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( - boost::shared_ptr theDirX, - boost::shared_ptr theDirY, - boost::shared_ptr theNorm) + std::shared_ptr theDirX, std::shared_ptr theDirY, + std::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)) + std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); + std::shared_ptr aDirY = std::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}; + 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 = myEntityAttrMap.find(theNorm); - std::vector::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise - if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created + std::map, Slvs_hEntity>::const_iterator aEntIter = + myEntityAttrMap.find(theNorm); + std::vector::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise + if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created aParamIter = myParams.end(); - else - { // the entity already exists, update it + 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; @@ -443,28 +782,27 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( for (int i = 0; i < 4; i++) aNormParams[i] = changeParameter(aNormCoord[i], aParamIter); - if (aEntIter != myEntityAttrMap.end()) // the entity already exists + if (aEntIter != myEntityAttrMap.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]); + Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1], + aNormParams[2], aNormParams[3]); myEntities.push_back(aNormal); + myEntOfConstr.push_back(false); myEntityAttrMap[theNorm] = aNormal.h; return aNormal.h; } - // ============================================================================ // Function: addWorkplane // Class: SketchSolver_ConstraintGroup // Purpose: create workplane for the group // ============================================================================ -bool SketchSolver_ConstraintGroup::addWorkplane( - boost::shared_ptr theSketch) +bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr theSketch) { - if (myWorkplane.h || theSketch->getKind().compare(SKETCH_KIND) != 0) - return false; // the workplane already exists or the function parameter is not Sketch + if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0) + return false; // the workplane already exists or the function parameter is not Sketch mySketch = theSketch; updateWorkplane(); @@ -478,23 +816,31 @@ bool SketchSolver_ConstraintGroup::addWorkplane( // ============================================================================ bool SketchSolver_ConstraintGroup::updateWorkplane() { + if (!mySketch->data()) + return false; // case sketch is deleted // 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); + std::shared_ptr aDirX = mySketch->data()->attribute( + SketchPlugin_Sketch::DIRX_ID()); + std::shared_ptr aDirY = mySketch->data()->attribute( + SketchPlugin_Sketch::DIRY_ID()); + std::shared_ptr aNorm = mySketch->data()->attribute( + SketchPlugin_Sketch::NORM_ID()); + std::shared_ptr anOrigin = mySketch->data()->attribute( + SketchPlugin_Sketch::ORIGIN_ID()); // Transform them into SolveSpace format Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm); - if (!aNormalWP) return false; + if (!aNormalWP) + return false; Slvs_hEntity anOriginWP = changeEntity(anOrigin); - if (!anOriginWP) return false; + if (!anOriginWP) + return false; - if (!myWorkplane.h) - { + 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); + myEntOfConstr.push_back(false); } return true; } @@ -505,15 +851,12 @@ bool SketchSolver_ConstraintGroup::updateWorkplane() // Purpose: create/update value of parameter // ============================================================================ Slvs_hParam SketchSolver_ConstraintGroup::changeParameter( - const double& theParam, - std::vector::const_iterator& thePrmIter) + const double& theParam, std::vector::const_iterator& thePrmIter) { - if (thePrmIter != myParams.end()) - { // Parameter should be updated + 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 + if (fabs(thePrmIter->val - theParam) > tolerance) { + myNeedToSolve = true; // parameter is changed, need to resolve constraints myParams[aParamPos].val = theParam; } thePrmIter++; @@ -534,10 +877,10 @@ Slvs_hParam SketchSolver_ConstraintGroup::changeParameter( // Class: SketchSolver_ConstraintGroup // Purpose: solve the set of constraints for the current group // ============================================================================ -void SketchSolver_ConstraintGroup::resolveConstraints() +bool SketchSolver_ConstraintGroup::resolveConstraints() { if (!myNeedToSolve) - return; + return false; myConstrSolver.setGroupID(myID); myConstrSolver.setParameters(myParams); @@ -546,22 +889,23 @@ void SketchSolver_ConstraintGroup::resolveConstraints() myConstrSolver.setDraggedParameters(myTempPointWhereDragged); int aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY) - { // solution succeeded, store results into correspondent attributes - // Obtain result into the same list of parameters + if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes + // Obtain result into the same list of parameters if (!myConstrSolver.getResult(myParams)) - return; + return true; // We should go through the attributes map, because only attributes have valued parameters - std::map, Slvs_hEntity>::iterator - anEntIter = myEntityAttrMap.begin(); - for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++) - updateAttribute(anEntIter->first, anEntIter->second); - } - /// \todo Implement error handling + std::map, Slvs_hEntity>::iterator anEntIter = + myEntityAttrMap.begin(); + for (; anEntIter != myEntityAttrMap.end(); anEntIter++) + if (updateAttribute(anEntIter->first, anEntIter->second)) + updateRelatedConstraints(anEntIter->first); + } else if (!myConstraints.empty()) + Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); removeTemporaryConstraints(); myNeedToSolve = false; + return true; } // ============================================================================ @@ -569,41 +913,37 @@ void SketchSolver_ConstraintGroup::resolveConstraints() // Class: SketchSolver_ConstraintGroup // Purpose: append specified group to the current group // ============================================================================ -void SketchSolver_ConstraintGroup::mergeGroups( - const SketchSolver_ConstraintGroup& theGroup) +void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup) { // If specified group is empty, no need to merge if (theGroup.myConstraintMap.empty()) - return ; + return; // Map between old and new indexes of SolveSpace constraints std::map aConstrMap; // Add all constraints from theGroup to the current group - std::map, Slvs_hConstraint>::const_iterator - aConstrIter = theGroup.myConstraintMap.begin(); - for ( ; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++) + ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin(); + for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++) if (changeConstraint(aConstrIter->first)) - aConstrMap[aConstrIter->second] = myConstrMaxID; // the constraint was added => store its ID + aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID // Add temporary constraints from theGroup std::list::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin(); - for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) - { - std::map::iterator aFind = aConstrMap.find(*aTempConstrIter); + for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) { + std::map::iterator aFind = aConstrMap.find( + *aTempConstrIter); if (aFind != aConstrMap.end()) myTempConstraints.push_back(aFind->second); } if (myTempPointWhereDragged.empty()) myTempPointWhereDragged = theGroup.myTempPointWhereDragged; - else if (!theGroup.myTempPointWhereDragged.empty()) - { // Need to create additional transient constraint - std::map, Slvs_hEntity>::const_iterator - aFeatureIter = theGroup.myEntityAttrMap.begin(); + else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint + std::map, Slvs_hEntity>::const_iterator aFeatureIter = + theGroup.myEntityAttrMap.begin(); for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++) - if (aFeatureIter->second == myTempPointWDrgdID) - { + if (aFeatureIter->second == myTempPointWDrgdID) { addTemporaryConstraintWhereDragged(aFeatureIter->first); break; } @@ -620,34 +960,45 @@ void SketchSolver_ConstraintGroup::mergeGroups( void SketchSolver_ConstraintGroup::splitGroup(std::vector& theCuts) { // Divide constraints and entities into several groups - std::vector< std::set > aGroupsEntities; - std::vector< std::set > aGroupsConstr; - int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current) + std::vector > aGroupsEntities; + std::vector > aGroupsConstr; + int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current) std::vector::const_iterator aConstrIter = myConstraints.begin(); - for ( ; aConstrIter != myConstraints.end(); aConstrIter++) - { - Slvs_hEntity aConstrEnt[] = { - aConstrIter->ptA, aConstrIter->ptB, - aConstrIter->entityA, aConstrIter->entityB}; + for (; aConstrIter != myConstraints.end(); aConstrIter++) { + Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, + aConstrIter->entityB }; std::vector anIndexes; // Go through the groupped entities and find even one of entities of current constraint - std::vector< std::set >::iterator aGrEntIter; - for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) - { + std::vector >::iterator aGrEntIter; + for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) { bool isFound = false; for (int i = 0; i < 4 && !isFound; i++) - if (aConstrEnt[i] != 0) + if (aConstrEnt[i] != 0) { isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end()); + // Also we need to check sub-entities + int aEntPos = Search(aConstrEnt[i], myEntities); + if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close + Slvs_hEntity* aSub = myEntities[aEntPos].point; + for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++) + isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end()); + } + } if (isFound) anIndexes.push_back(aGrEntIter - aGroupsEntities.begin()); } // Add new group if no one is found - if (anIndexes.empty()) - { + if (anIndexes.empty()) { std::set aNewGrEnt; for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != 0) + if (aConstrEnt[i] != 0) { aNewGrEnt.insert(aConstrEnt[i]); + int aEntPos = Search(aConstrEnt[i], myEntities); + if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close + Slvs_hEntity* aSub = myEntities[aEntPos].point; + for (int j = 0; *aSub != 0 && j < 4; aSub++, j++) + aNewGrEnt.insert(*aSub); + } + } std::set aNewGrConstr; aNewGrConstr.insert(aConstrIter->h); @@ -655,42 +1006,44 @@ void SketchSolver_ConstraintGroup::splitGroup(std::vector aGroupsEntities[aMaxNbEntities].size()) aMaxNbEntities = aGroupsEntities.size() - 1; - } - else if (anIndexes.size() == 1) - { // Add entities indexes into the found group + } else { // Add entities indexes into the found group aGrEntIter = aGroupsEntities.begin() + anIndexes.front(); for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != 0) + if (aConstrEnt[i] != 0) { aGrEntIter->insert(aConstrEnt[i]); + int aEntPos = Search(aConstrEnt[i], myEntities); + if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close + Slvs_hEntity* aSub = myEntities[aEntPos].point; + for (int j = 0; *aSub != 0 && j < 4; aSub++, j++) + aGrEntIter->insert(*aSub); + } + } aGroupsConstr[anIndexes.front()].insert(aConstrIter->h); if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size()) aMaxNbEntities = aGrEntIter - aGroupsEntities.begin(); - } - else - { // There are found several connected groups, merge them - std::vector< std::set >::iterator aFirstGroup = - aGroupsEntities.begin() + anIndexes.front(); - std::vector< std::set >::iterator aFirstConstr = - aGroupsConstr.begin() + anIndexes.front(); - std::vector::iterator anInd = anIndexes.begin(); - for (++anInd; anInd != anIndexes.end(); anInd++) - { - aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end()); - aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end()); - } - if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size()) - aMaxNbEntities = anIndexes.front(); - // Remove merged groups - for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) - { - aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd)); - aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd)); + if (anIndexes.size() > 1) { // There are found several connected groups, merge them + std::vector >::iterator aFirstGroup = aGroupsEntities.begin() + + anIndexes.front(); + std::vector >::iterator aFirstConstr = aGroupsConstr.begin() + + anIndexes.front(); + std::vector::iterator anInd = anIndexes.begin(); + for (++anInd; anInd != anIndexes.end(); anInd++) { + aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end()); + aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end()); + } + if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size()) + aMaxNbEntities = anIndexes.front(); + // Remove merged groups + for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) { + aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd)); + aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd)); + } } } } if (aGroupsEntities.size() <= 1) - return ; + return; // Remove the group with maximum elements as it will be left in the current group aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities); @@ -698,21 +1051,17 @@ void SketchSolver_ConstraintGroup::splitGroup(std::vector aNewGroups; - for (int i = aGroupsEntities.size(); i > 0; i--) - { + for (int i = aGroupsEntities.size(); i > 0; i--) { SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch); aNewGroups.push_back(aG); } - std::map, Slvs_hConstraint>::const_iterator - aConstrMapIter = myConstraintMap.begin(); - int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint) - while (aConstrMapIter != myConstraintMap.end()) - { - std::vector< std::set >::const_iterator aGIter = aGroupsConstr.begin(); + ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin(); + int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint) + while (aConstrMapIter != myConstraintMap.end()) { + std::vector >::const_iterator aGIter = aGroupsConstr.begin(); std::vector::iterator aGroup = aNewGroups.begin(); - for ( ; aGIter != aGroupsConstr.end(); aGIter++, aGroup++) - if (aGIter->find(aConstrMapIter->second) != aGIter->end()) - { + for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++) + if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) { (*aGroup)->changeConstraint(aConstrMapIter->first); removeConstraint(aConstrMapIter->first); // restore iterator @@ -721,8 +1070,7 @@ void SketchSolver_ConstraintGroup::splitGroup(std::vector, Slvs_hConstraint>::reverse_iterator - aConstrIter = myConstraintMap.rbegin(); + ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin(); bool isAllValid = true; - bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed - while (isAllValid && aConstrIter != myConstraintMap.rend()) - { - if (!aConstrIter->first->data()->isValid()) - { - if (aConstrIter->first->getKind().compare(SKETCH_CONSTRAINT_COINCIDENCE_KIND) == 0) + bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed + int aConstrIndex = 0; + while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) { + if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) { + if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) isCCRemoved = true; - std::map, Slvs_hConstraint>::reverse_iterator - aCopyIter = aConstrIter++; - removeConstraint(aCopyIter->first); + removeConstraint(aConstrIter->first); isAllValid = false; + // Get back the correct position of iterator after the "remove" operation + aConstrIter = myConstraintMap.rbegin(); + for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++) + aConstrIter++; + } else { + aConstrIter++; + aConstrIndex++; } - else aConstrIter++; } + // Check if some entities are invalid too + std::set anEntToRemove; + std::map, Slvs_hEntity>::iterator + anAttrIter = myEntityAttrMap.begin(); + while (anAttrIter != myEntityAttrMap.end()) { + if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() || + !anAttrIter->first->owner()->data()->isValid()) { + anEntToRemove.insert(anAttrIter->second); + std::map, Slvs_hEntity>::iterator + aRemovedIter = anAttrIter; + anAttrIter++; + myEntityAttrMap.erase(aRemovedIter); + } else + anAttrIter++; + } + std::map::iterator aFeatIter = myEntityFeatMap.begin(); + while (aFeatIter != myEntityFeatMap.end()) { + if (!aFeatIter->first || !aFeatIter->first->data() || + !aFeatIter->first->data()->isValid()) { + anEntToRemove.insert(aFeatIter->second); + std::map::iterator aRemovedIter = aFeatIter; + aFeatIter++; + myEntityFeatMap.erase(aRemovedIter); + } else + aFeatIter++; + } + removeEntitiesById(anEntToRemove); + // Probably, need to update coincidence constraints - if (isCCRemoved && !myExtraCoincidence.empty()) - { + if (isCCRemoved && !myExtraCoincidence.empty()) { // Make a copy, because the new list of unused constrtaints will be generated - std::set< boost::shared_ptr > anExtraCopy = myExtraCoincidence; + std::set > anExtraCopy = myExtraCoincidence; myExtraCoincidence.clear(); - std::set< boost::shared_ptr >::iterator - aCIter = anExtraCopy.begin(); - for ( ; aCIter != anExtraCopy.end(); aCIter++) - if ((*aCIter)->data()->isValid()) + std::set >::iterator aCIter = anExtraCopy.begin(); + for (; aCIter != anExtraCopy.end(); aCIter++) + if ((*aCIter)->data() && (*aCIter)->data()->isValid()) changeConstraint(*aCIter); } @@ -778,9 +1154,8 @@ bool SketchSolver_ConstraintGroup::updateGroup() // Class: SketchSolver_ConstraintGroup // Purpose: update features of sketch after resolving constraints // ============================================================================ -void SketchSolver_ConstraintGroup::updateAttribute( - boost::shared_ptr theAttribute, - const Slvs_hEntity& theEntityID) +bool SketchSolver_ConstraintGroup::updateAttribute( + std::shared_ptr theAttribute, const Slvs_hEntity& theEntityID) { // Search the position of the first parameter of the entity int anEntPos = Search(theEntityID, myEntities); @@ -789,36 +1164,43 @@ void SketchSolver_ConstraintGroup::updateAttribute( // 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 ; + std::shared_ptr aPoint = std::dynamic_pointer_cast( + theAttribute); + if (aPoint) { + if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance + || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance + || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) { + aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val, + myParams[aFirstParamPos + 2].val); + return true; + } + return false; } // Point in 2D - boost::shared_ptr aPoint2D = - boost::dynamic_pointer_cast(theAttribute); - if (aPoint2D) - { - aPoint2D->setValue(myParams[aFirstParamPos].val, - myParams[aFirstParamPos+1].val); - return ; + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theAttribute); + if (aPoint2D) { + if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance + || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) { + aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val); + return true; + } + return false; } // Scalar value - boost::shared_ptr aScalar = - boost::dynamic_pointer_cast(theAttribute); - if (aScalar) - { - aScalar->setValue(myParams[aFirstParamPos].val); - return ; + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); + if (aScalar) { + if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) { + aScalar->setValue(myParams[aFirstParamPos].val); + return true; + } + return false; } /// \todo Support other types of entities + return false; } // ============================================================================ @@ -827,10 +1209,9 @@ void SketchSolver_ConstraintGroup::updateAttribute( // Purpose: search the entity in this group and update it // ============================================================================ void SketchSolver_ConstraintGroup::updateEntityIfPossible( - boost::shared_ptr theEntity) + std::shared_ptr theEntity) { - if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) - { + if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.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 guarantee the point will not change @@ -841,19 +1222,22 @@ void SketchSolver_ConstraintGroup::updateEntityIfPossible( changeEntity(theEntity); - if (myNeedToSolve) // the entity is changed + 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); + std::shared_ptr aPoint = std::dynamic_pointer_cast( + theEntity); + std::shared_ptr aPoint2D = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(theEntity); if (aPoint || aPoint2D) addTemporaryConstraintWhereDragged(theEntity); } // Restore flag of changes myNeedToSolve = myNeedToSolve || aNeedToSolveCopy; + + if (myNeedToSolve) + updateRelatedConstraints(theEntity); } } @@ -864,49 +1248,53 @@ void SketchSolver_ConstraintGroup::updateEntityIfPossible( // which was moved by user // ============================================================================ void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged( - boost::shared_ptr theEntity) + std::shared_ptr theEntity, + bool theAllowToFit) { // Find identifier of the entity - std::map, Slvs_hEntity>::const_iterator - anEntIter = myEntityAttrMap.find(theEntity); + std::map, Slvs_hEntity>::const_iterator anEntIter = + myEntityAttrMap.find(theEntity); if (anEntIter == myEntityAttrMap.end()) - return ; - - // If this is a first dragged point, its parameters should be placed - // into Slvs_System::dragged field to avoid system inconsistense - if (myTempPointWhereDragged.empty()) - { - int anEntPos = Search(anEntIter->second, myEntities); - Slvs_hParam* aDraggedParam = myEntities[anEntPos].param; - for (int i = 0; i < 4; i++, aDraggedParam++) - if (*aDraggedParam != 0) - myTempPointWhereDragged.push_back(*aDraggedParam); - myTempPointWDrgdID = myEntities[anEntPos].h; - return ; - } + return; // Get identifiers of all dragged points std::set aDraggedPntID; aDraggedPntID.insert(myTempPointWDrgdID); - std::list::iterator aTmpCoIter = myTempConstraints.begin(); - for ( ; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) - { + std::list::const_iterator aTmpCoIter = myTempConstraints.begin(); + for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) { unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints); if (aConstrPos < myConstraints.size()) aDraggedPntID.insert(myConstraints[aConstrPos].ptA); } + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) + aDraggedPntID.insert(aConstrIter->ptA); // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED - std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); - for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) - { + std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); + for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) { if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end()) - continue; // the entity was not found in current set + continue; // the entity was not found in current set // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points std::set::const_iterator aDrgIter = aDraggedPntID.begin(); - for ( ; aDrgIter != aDraggedPntID.end(); aDrgIter++) + for (; aDrgIter != aDraggedPntID.end(); aDrgIter++) if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end()) - return ; // the SLVS_C_WHERE_DRAGGED constraint already exists + return; // the SLVS_C_WHERE_DRAGGED constraint already exists + } + if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end()) + return; + + // If this is a first dragged point, its parameters should be placed + // into Slvs_System::dragged field to avoid system inconsistense + if (myTempPointWhereDragged.empty() && theAllowToFit) { + int anEntPos = Search(anEntIter->second, myEntities); + Slvs_hParam* aDraggedParam = myEntities[anEntPos].param; + for (int i = 0; i < 4; i++, aDraggedParam++) + if (*aDraggedParam != 0) + myTempPointWhereDragged.push_back(*aDraggedParam); + myTempPointWDrgdID = myEntities[anEntPos].h; + return; } // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty @@ -922,11 +1310,14 @@ void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged( // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after // resolving the set of constraints // ============================================================================ -void SketchSolver_ConstraintGroup::removeTemporaryConstraints() +void SketchSolver_ConstraintGroup::removeTemporaryConstraints( + const std::set& theRemoved) { std::list::reverse_iterator aTmpConstrIter; - for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++) - { + for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); + aTmpConstrIter++) { + if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end()) + continue; unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints); if (aConstrPos >= myConstraints.size()) continue; @@ -940,6 +1331,7 @@ void SketchSolver_ConstraintGroup::removeTemporaryConstraints() // Clear basic dragged point myTempPointWhereDragged.clear(); + myTempPointWDrgdID = SLVS_E_UNKNOWN; } // ============================================================================ @@ -947,119 +1339,141 @@ void SketchSolver_ConstraintGroup::removeTemporaryConstraints() // Class: SketchSolver_ConstraintGroup // Purpose: remove constraint and all unused entities // ============================================================================ -void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr theConstraint) +void SketchSolver_ConstraintGroup::removeConstraint( + std::shared_ptr theConstraint) { - std::map, Slvs_hConstraint>::iterator - anIterToRemove = myConstraintMap.find(theConstraint); + ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint); if (anIterToRemove == myConstraintMap.end()) - return ; + return; - Slvs_hConstraint aCnstrToRemove = anIterToRemove->second; + std::vector aCnstrToRemove = anIterToRemove->second; // Remove constraint from the map myConstraintMap.erase(anIterToRemove); - // Find unused entities - int aConstrPos = Search(aCnstrToRemove, myConstraints); std::set anEntToRemove; - Slvs_hEntity aCnstEnt[] = {myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, - myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB}; - for (int i = 0; i < 4; i++) - if (aCnstEnt[i] != 0) - anEntToRemove.insert(aCnstEnt[i]); - myConstraints.erase(myConstraints.begin() + aConstrPos); - if (aCnstrToRemove == myConstrMaxID) - myConstrMaxID--; + + // Find unused entities + std::vector::iterator aCnstrToRemoveIter = aCnstrToRemove.begin(); + for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) { + int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints); + Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, + myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB }; + for (int i = 0; i < 4; i++) + if (aCnstEnt[i] != 0) + anEntToRemove.insert(aCnstEnt[i]); + myConstraints.erase(myConstraints.begin() + aConstrPos); + if (*aCnstrToRemoveIter == myConstrMaxID) + myConstrMaxID--; + } + + // Find all entities which are based on these unused + std::vector::const_iterator anEntIter = myEntities.begin(); + for ( ; anEntIter != myEntities.end(); anEntIter++) + if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE || + anEntIter->type == SLVS_E_ARC_OF_CIRCLE) { + for (int i = 0; i < 4; i++) + if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) { + anEntToRemove.insert(anEntIter->h); + for (int j = 0; j < 4; j++) + if (anEntIter->param[j] != 0) + anEntToRemove.insert(anEntIter->point[j]); + break; + } + } + std::vector::const_iterator aConstrIter = myConstraints.begin(); - for ( ; aConstrIter != myConstraints.end(); aConstrIter++) - { - Slvs_hEntity aEnts[] = {aConstrIter->ptA, aConstrIter->ptB, - aConstrIter->entityA, aConstrIter->entityB}; + for (; aConstrIter != myConstraints.end(); aConstrIter++) { + Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter + ->entityB }; for (int i = 0; i < 4; i++) if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) anEntToRemove.erase(aEnts[i]); } if (anEntToRemove.empty()) - return ; + return; // Remove unused entities - std::map, Slvs_hEntity>::iterator - anEntAttrIter = myEntityAttrMap.begin(); - while (anEntAttrIter != myEntityAttrMap.end()) - { - if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) - { - std::map, Slvs_hEntity>::iterator - aRemovedIter = anEntAttrIter; + std::map, Slvs_hEntity>::iterator anEntAttrIter = + myEntityAttrMap.begin(); + while (anEntAttrIter != myEntityAttrMap.end()) { + if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) { + std::map, Slvs_hEntity>::iterator aRemovedIter = + anEntAttrIter; anEntAttrIter++; myEntityAttrMap.erase(aRemovedIter); - } - else anEntAttrIter++; + } else + anEntAttrIter++; } - std::map::iterator - anEntFeatIter = myEntityFeatMap.begin(); - while (anEntFeatIter != myEntityFeatMap.end()) - { - if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) - { - std::map::iterator - aRemovedIter = anEntFeatIter; + std::map::iterator anEntFeatIter = myEntityFeatMap.begin(); + while (anEntFeatIter != myEntityFeatMap.end()) { + if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) { + std::map::iterator aRemovedIter = anEntFeatIter; anEntFeatIter++; myEntityFeatMap.erase(aRemovedIter); - } - else anEntFeatIter++; + } else + anEntFeatIter++; } - std::set::const_reverse_iterator aRemIter = anEntToRemove.rbegin(); - for ( ; aRemIter != anEntToRemove.rend(); aRemIter++) - { + + removeEntitiesById(anEntToRemove); + + if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty()) + myCoincidentPoints.clear(); +} + +// ============================================================================ +// Function: removeEntitiesById +// Class: SketchSolver_ConstraintGroup +// Purpose: Removes specified entities and their parameters +// ============================================================================ +void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set& theEntities) +{ + std::set::const_reverse_iterator aRemIter = theEntities.rbegin(); + for (; aRemIter != theEntities.rend(); aRemIter++) { unsigned int anEntPos = Search(*aRemIter, myEntities); if (anEntPos >= myEntities.size()) continue; - unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); - if (aParamPos >= myParams.size()) - continue; - int aNbParams = 0; - while (myEntities[anEntPos].param[aNbParams] != 0) - aNbParams++; - if (myEntities[anEntPos].param[aNbParams-1] == myParamMaxID) - myParamMaxID -= aNbParams; - myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); - if (*aRemIter == myEntityMaxID) - myEntityMaxID--; + if (myEntities[anEntPos].param[0] != 0) { + unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); + if (aParamPos >= myParams.size()) + continue; + int aNbParams = 0; + while (myEntities[anEntPos].param[aNbParams] != 0) + aNbParams++; + if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID) + myParamMaxID -= aNbParams; + myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); + if (*aRemIter == myEntityMaxID) + myEntityMaxID--; + } myEntities.erase(myEntities.begin() + anEntPos); + myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos); // Remove entity's ID from the lists of conincident points - std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); - for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) + std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); + for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) aCoPtIter->erase(*aRemIter); } - if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty()) - myCoincidentPoints.clear(); } - // ============================================================================ // Function: addCoincidentPoints // Class: SketchSolver_ConstraintGroup // Purpose: add coincident point the appropriate list of such points // ============================================================================ -bool SketchSolver_ConstraintGroup::addCoincidentPoints( - const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) +bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1, + const Slvs_hEntity& thePoint2) { - std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); - std::vector< std::set >::iterator aFirstFound = myCoincidentPoints.end(); - while (aCoPtIter != myCoincidentPoints.end()) - { - bool isFound[2] = { // indicate which point ID was already in coincidence constraint - aCoPtIter->find(thePoint1) != aCoPtIter->end(), - aCoPtIter->find(thePoint2) != aCoPtIter->end(), - }; - if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one + std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); + std::vector >::iterator aFirstFound = myCoincidentPoints.end(); + while (aCoPtIter != myCoincidentPoints.end()) { + bool isFound[2] = { // indicate which point ID was already in coincidence constraint + aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2) + != aCoPtIter->end(), }; + if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one return false; - if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) - { - if (aFirstFound != myCoincidentPoints.end()) - { // there are two groups of coincident points connected by created constraint => merge them + if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) { + if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin(); int aCurrentShift = aCoPtIter - myCoincidentPoints.begin(); aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end()); @@ -1067,9 +1481,7 @@ bool SketchSolver_ConstraintGroup::addCoincidentPoints( aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift; aCoPtIter = myCoincidentPoints.begin() + aCurrentShift; continue; - } - else - { + } else { aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1); aFirstFound = aCoPtIter; } @@ -1077,8 +1489,7 @@ bool SketchSolver_ConstraintGroup::addCoincidentPoints( aCoPtIter++; } // No points were found, need to create new set - if (aFirstFound == myCoincidentPoints.end()) - { + if (aFirstFound == myCoincidentPoints.end()) { std::set aNewSet; aNewSet.insert(thePoint1); aNewSet.insert(thePoint2); @@ -1088,21 +1499,69 @@ bool SketchSolver_ConstraintGroup::addCoincidentPoints( return true; } +// ============================================================================ +// Function: updateRelatedConstraints +// Class: SketchSolver_ConstraintGroup +// Purpose: emit the signal to update constraints +// ============================================================================ +void SketchSolver_ConstraintGroup::updateRelatedConstraints( + std::shared_ptr theEntity) const +{ + ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); + for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { + std::list > anAttributes = aConstrIter->first->data() + ->attributes(std::string()); + + std::list >::iterator anAttrIter = anAttributes.begin(); + for (; anAttrIter != anAttributes.end(); anAttrIter++) { + bool isUpd = (*anAttrIter == theEntity); + std::shared_ptr aRefAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>(*anAttrIter); + if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity) + isUpd = true; + + if (isUpd) { + static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); + break; + } + } + } +} - +void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature( + std::shared_ptr theFeature) const +{ + ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); + for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { + std::list > anAttributes = aConstrIter->first->data() + ->attributes(std::string()); + + std::list >::iterator anAttrIter = anAttributes.begin(); + for (; anAttrIter != anAttributes.end(); anAttrIter++) { + std::shared_ptr aRefAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>(*anAttrIter); + if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) { + static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); + break; + } + } + } +} // ======================================================== // ========= Auxiliary functions =============== // ======================================================== -template +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) + while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) aResIndex++; if (aResIndex == -1) aResIndex = aVecSize;