From 394ab282ef36885ebe6e2473019d994ef1b17652 Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 10 Apr 2015 15:03:57 +0300 Subject: [PATCH] Avoid conflicting constraints when mirror a group of entities with Equal constraint --- .../SketchSolver_ConstraintRigid.cpp | 54 ++---- .../SketchSolver_ConstraintRigid.h | 3 - src/SketchSolver/SketchSolver_Group.cpp | 18 +- src/SketchSolver/SketchSolver_Storage.cpp | 157 ++++++++++++++++-- src/SketchSolver/SketchSolver_Storage.h | 14 +- 5 files changed, 189 insertions(+), 57 deletions(-) diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp index 7f12c7d32..3483973fe 100644 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp @@ -148,12 +148,12 @@ void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) return; Slvs_Constraint aConstraint; - Slvs_hConstraint aConstrID = myStorage->isPointFixed(thePointID); - bool isForceUpdate = (aConstrID != SLVS_E_UNKNOWN && !myBaseConstraint && + Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; + bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true); + bool isForceUpdate = (isFixed && !myBaseConstraint && myStorage->isTemporary(aConstrID)); if (!isForceUpdate) { // create new constraint - if (aConstrID != SLVS_E_UNKNOWN) - return; // the coincident point is already fixed + if (isFixed) return; aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); aConstraint.h = myStorage->addConstraint(aConstraint); @@ -161,7 +161,7 @@ void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) if (!myBaseConstraint) myStorage->addConstraintWhereDragged(aConstraint.h); } else { // update already existent constraint - if (aConstrID == SLVS_E_UNKNOWN || myBaseConstraint) + if (!isFixed || aConstrID == SLVS_E_UNKNOWN || myBaseConstraint) return; aConstraint = myStorage->getConstraint(aConstrID); aConstraint.ptA = thePointID; @@ -177,11 +177,11 @@ void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine) if (isUsedInEqual(theLine, anEqual)) { // Check another entity of Equal is already fixed Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA; - Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID); - if (isFixed(anOtherEntity)) { + if (myStorage->isEntityFixed(anOtherEntID, true)) { // Fix start point of the line (if end point is not fixed yet) ... - Slvs_hConstraint anEndFixedID = myStorage->isPointFixed(theLine.point[1]); - if (anEndFixedID == SLVS_E_UNKNOWN) + Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN; + bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true); + if (isFixed == SLVS_E_UNKNOWN) fixPoint(theLine.point[0]); // ... and create fixed point lying on this line Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0]; @@ -192,7 +192,7 @@ void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine) std::list::const_iterator aPLIter = aPonLineList.begin(); for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++) if (aPLIter->entityA == theLine.h) { - isPonLineFixed = (myStorage->isPointFixed(aPLIter->ptA) != SLVS_E_UNKNOWN); + isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID); aFixedPoint = aPLIter->ptA; } @@ -222,8 +222,7 @@ void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle) if (isUsedInEqual(theCircle, anEqual)) { // Check another entity of Equal is already fixed Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA; - Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID); - if (isFixed(anOtherEntity)) + if (myStorage->isEntityFixed(anOtherEntID, true)) isFixRadius = false; } @@ -253,9 +252,9 @@ void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc) if (isUsedInEqual(theArc, anEqual)) { // Check another entity of Equal is already fixed Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA; - Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID); - if (isFixed(anOtherEntity)) { + if (myStorage->isEntityFixed(anOtherEntID, true)) { isFixRadius = false; + Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID); if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) { aPointsToFix.pop_back(); aPointsToFix.push_back(theArc.point[0]); @@ -263,9 +262,9 @@ void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc) } } - Slvs_hConstraint aConstrID = myStorage->isPointFixed(theArc.point[0]); + Slvs_hConstraint aConstrID; int aNbPointsToFix = 2; // number of fixed points for the arc - if (aConstrID != SLVS_E_UNKNOWN) + if (myStorage->isPointFixed(theArc.point[0], aConstrID, true)) aNbPointsToFix--; // Radius of the arc @@ -336,26 +335,3 @@ bool SketchSolver_ConstraintRigid::isUsedInEqual( return false; } -bool SketchSolver_ConstraintRigid::isFixed(const Slvs_Entity& theEntity) const -{ - if (theEntity.type == SLVS_E_POINT_IN_2D) - return myStorage->isPointFixed(theEntity.h) != SLVS_E_UNKNOWN; - - // Check all the points of entity are fixed - int aNbFixed = 0; - for (int i = 0; i < 4; i++) { - if (theEntity.point[i] != SLVS_E_UNKNOWN && - myStorage->isPointFixed(theEntity.point[i]) != SLVS_E_UNKNOWN) - aNbFixed++; - } - - switch (theEntity.type) { - case SLVS_E_LINE_SEGMENT: - case SLVS_E_ARC_OF_CIRCLE: - if (aNbFixed == 2) return true; - case SLVS_E_CIRCLE: - if (aNbFixed == 1) return true; - } - return false; -} - diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h index 93de58362..4cde52479 100644 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.h +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.h @@ -67,9 +67,6 @@ private: /// \return \c true, if the Equal constrait is found bool isUsedInEqual(const Slvs_Entity& theEntity, Slvs_Constraint& theEqual) const; - /// \brief Verifies the entity is already fixed - bool isFixed(const Slvs_Entity& theEntity) const; - protected: FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL) }; diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 3c5832cdb..9ccf3fa73 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -289,12 +290,27 @@ void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList) { std::list aList = theList->list(); std::list::iterator anIt = aList.begin(); + std::list aFeatures; + // Sort features, at begining there are features used by Equal constraint for (; anIt != aList.end(); anIt++) { if (!(*anIt)) continue; FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + std::set aConstraints = myFeatureStorage->getConstraints(aFeature); + std::set::iterator aCIter = aConstraints.begin(); + for (; aCIter != aConstraints.end(); aCIter++) + if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID()) + break; + if (aCIter != aConstraints.end()) + aFeatures.push_front(aFeature); + else + aFeatures.push_back(aFeature); + } + + std::list::iterator aFeatIter = aFeatures.begin(); + for (; aFeatIter != aFeatures.end(); aFeatIter++) { SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); + SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter); if (!aConstraint) continue; aConstraint->setGroup(this); diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index f13ad6b6f..eddd630c9 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -246,31 +246,164 @@ void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hE } -Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const +bool SketchSolver_Storage::isPointFixed( + const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const { // Search the set of coincident points + std::set aCoincident; + aCoincident.insert(thePointID); std::vector< std::set >::const_iterator aCPIter = myCoincidentPoints.begin(); for (; aCPIter != myCoincidentPoints.end(); aCPIter++) - if (aCPIter->find(thePointID) != aCPIter->end()) + if (aCPIter->find(thePointID) != aCPIter->end()) { + aCoincident = *aCPIter; break; - if (aCPIter == myCoincidentPoints.end()) { - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && - aConstrIter->ptA == thePointID) - return aConstrIter->h; - return SLVS_E_UNKNOWN; - } + } // Search the Rigid constraint std::vector::const_iterator aConstrIter = myConstraints.begin(); for (; aConstrIter != myConstraints.end(); aConstrIter++) if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && - aCPIter->find(aConstrIter->ptA) != aCPIter->end()) - return aConstrIter->h; + aCoincident.find(aConstrIter->ptA) != aCoincident.end()) { + theFixed = aConstrIter->h; + return true; + } + + if (theAccurate) { + // Try to find the fixed entity which uses such point or its coincidence + std::vector::const_iterator anEntIter = myEntities.begin(); + for (; anEntIter != myEntities.end(); anEntIter++) { + for (int i = 0; i < 4; i++) { + Slvs_hEntity aPt = anEntIter->point[i]; + if (aPt != SLVS_E_UNKNOWN && + (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) { + if (isEntityFixed(anEntIter->h, true)) + return true; + } + } + } + } return SLVS_E_UNKNOWN; } +bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const +{ + int aPos = Search(theEntityID, myEntities); + if (aPos < 0 || aPos >= (int)myEntities.size()) + return false; + + // Firstly, find how many points are under Rigid constraint + int aNbFixed = 0; + for (int i = 0; i < 4; i++) { + Slvs_hEntity aPoint = myEntities[aPos].point[i]; + if (aPoint == SLVS_E_UNKNOWN) + continue; + + std::set aCoincident; + aCoincident.insert(aPoint); + std::vector< std::set >::const_iterator aCPIter = myCoincidentPoints.begin(); + for (; aCPIter != myCoincidentPoints.end(); aCPIter++) + if (aCPIter->find(aPoint) != aCPIter->end()) { + aCoincident = *aCPIter; + break; + } + + // Search the Rigid constraint + 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()) + aNbFixed++; + } + + std::list aList; + std::list::iterator anIt; + Slvs_hConstraint aTempID; // used in isPointFixed() method + + if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) { + if (aNbFixed == 2) + return true; + else if (aNbFixed == 0 || !theAccurate) + return false; + // Additional check (the line may be fixed if it is used by different constraints): + // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line + aList = getConstraintsByType(SLVS_C_PT_ON_LINE); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID)) + break; + if (anIt != aList.end()) { + aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + } + // 2. The line is used in Parallel/Perpendicular and Length constraints + aList = getConstraintsByType(SLVS_C_PARALLEL); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + break; + } + if (anIt != aList.end()) { + aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) || + (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0])) + return true; + } + // 3. Another verifiers ... + } else if (myEntities[aPos].type == SLVS_E_CIRCLE) { + if (aNbFixed == 0) + return false; + // Search for Diameter constraint + aList = getConstraintsByType(SLVS_C_DIAMETER); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID) + return true; + if (!theAccurate) + return false; + // Additional check (the circle may be fixed if it is used by different constraints): + // 1. The circle is used in Equal constraint and another entity is fixed + aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + // 2. Another verifiers ... + } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) { + if (aNbFixed > 2) + return true; + else if (aNbFixed <= 1) + return false; + // Search for Diameter constraint + aList = getConstraintsByType(SLVS_C_DIAMETER); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID) + return true; + if (!theAccurate) + return false; + // Additional check (the arc may be fixed if it is used by different constraints): + // 1. The arc is used in Equal constraint and another entity is fixed + aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + // 2. Another verifiers ... + } + return false; +} + Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint) { diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index 613e0ec29..80fce4563 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -66,8 +66,18 @@ public: void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo); /// \brief Verifies the current point or another coincident one is fixed - /// \return the ID of the Fixed constraint or SLVS_E_UNKNOWN - Slvs_hConstraint isPointFixed(const Slvs_hEntity& thePointID) const; + /// \param[in] thePointID entity to be checked fixed + /// \param[out] theFixed ID of constraint + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only the point is verified + /// \return \c true if the point is fixed + bool isPointFixed(const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate = false) const; + /// \brief Verifies the current entity is fully fixed (may not be changed by constraints) + /// \param[in] theEntityID entity to be checked fixed + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only points are verified + /// \return \c true if the entity is fixed + bool isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate = false) const; /** \brief Add new constraint to the current group * \param[in] theConstraint SolveSpace's constraint -- 2.39.2