From 6b82f436079f958ed743771a9ae91a7fd99b632e Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 27 Nov 2015 16:27:41 +0300 Subject: [PATCH] Do not allow user to move fixed entities (issue #1043) --- src/SketchSolver/SketchSolver_Constraint.cpp | 8 + .../SketchSolver_ConstraintMovement.cpp | 74 ++++++++- .../SketchSolver_ConstraintMovement.h | 5 +- .../SketchSolver_ConstraintRigid.cpp | 144 +++++++++--------- .../SketchSolver_ConstraintRigid.h | 21 ++- src/SketchSolver/SketchSolver_Group.cpp | 13 +- src/SketchSolver/SketchSolver_Storage.cpp | 8 + src/SketchSolver/SketchSolver_Storage.h | 6 + 8 files changed, 193 insertions(+), 86 deletions(-) diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 11cdff04b..b4b888fa3 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -394,6 +394,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& } Slvs_hGroup aGroupID = myGroup->getId(); + // do not update entity from another group + if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group) + return aCurrentEntity.h; + // Point in 3D std::shared_ptr aPoint = std::dynamic_pointer_cast(theEntity); @@ -488,6 +492,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th } Slvs_hGroup aGroupID = myGroup->getId(); + // do not update entity from another group + if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group) + return aCurrentEntity.h; + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); DataPtr aData = theEntity->data(); diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp index 030274ac2..b97d1a754 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp @@ -2,6 +2,11 @@ #include #include +#include +#include +#include +#include + SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature) : SketchSolver_ConstraintRigid(theFeature) { @@ -45,6 +50,7 @@ void SketchSolver_ConstraintMovement::getAttributes( theIsFullyMoved = true; int aType = SLVS_E_UNKNOWN; // type of created entity Slvs_hEntity anEntityID = SLVS_E_UNKNOWN; + Slvs_hEntity anEntMaxID = myStorage->entityMaxID(); anEntityID = myGroup->getFeatureId(myBaseFeature); if (anEntityID == SLVS_E_UNKNOWN) { anEntityID = changeEntity(myBaseFeature, aType); @@ -65,17 +71,28 @@ void SketchSolver_ConstraintMovement::getAttributes( isComplexFeature = true; } + int aNbOutOfGroup = 0; if (isComplexFeature) { std::list aPoints = myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); std::list::iterator anIt = aPoints.begin(); for (; anIt != aPoints.end(); ++anIt) { - Slvs_hEntity anAttr = myGroup->getAttributeId(*anIt); + std::map::const_iterator aFound = myAttributeMap.find(*anIt); + Slvs_hEntity anAttr = aFound != myAttributeMap.end() ? + aFound->second : myGroup->getAttributeId(*anIt); + Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr); // Check the attribute changes coordinates std::shared_ptr aPt = std::dynamic_pointer_cast(*anIt); - if (isMoved(aPt, anAttr)) { + // Check the entity is not lying in the current group or it is not moved + if (anAttr == SLVS_E_UNKNOWN || anAttrEnt.group != myGroup->getId() || + (anAttr <= anEntMaxID && !isMoved(aPt, anAttrEnt))) { + if (anAttrEnt.group == SLVS_G_OUTOFGROUP) + ++aNbOutOfGroup; + theIsFullyMoved = false; + } + else { theAttributes.push_back(anAttr); // update point coordinates Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr); @@ -86,11 +103,21 @@ void SketchSolver_ConstraintMovement::getAttributes( myStorage->updateParameter(aParam); } } - else - theIsFullyMoved = false; } } + // Additional checking, which leads to fix whole feature, if it has fixed points + if (!theIsFullyMoved) { + Slvs_Entity aFeature = myStorage->getEntity(anEntityID); + int aNbPoints = 4; + while (aNbPoints > 0 && aFeature.point[aNbPoints-1] == SLVS_E_UNKNOWN) + --aNbPoints; + if (aNbPoints == aNbOutOfGroup + (int)theAttributes.size()) { + theIsFullyMoved = true; + return; + } + } + // Leave only points which are used in constraints if (myStorage->isUsedByConstraints(anEntityID)) return; @@ -107,12 +134,43 @@ void SketchSolver_ConstraintMovement::getAttributes( } bool SketchSolver_ConstraintMovement::isMoved( - std::shared_ptr thePoint, Slvs_hEntity theEntity) + std::shared_ptr thePoint, const Slvs_Entity& theEntity) { - Slvs_Entity anAttrEnt = myStorage->getEntity(theEntity); - double aDeltaX = myStorage->getParameter(anAttrEnt.param[0]).val; - double aDeltaY = myStorage->getParameter(anAttrEnt.param[1]).val; + double aDeltaX = myStorage->getParameter(theEntity.param[0]).val; + double aDeltaY = myStorage->getParameter(theEntity.param[1]).val; aDeltaX -= thePoint->x(); aDeltaY -= thePoint->y(); return aDeltaX * aDeltaX + aDeltaY * aDeltaY >= tolerance * tolerance; } + +void SketchSolver_ConstraintMovement::fixFeature() +{ + Slvs_hEntity anEntID = fixedEntity(); + + std::string aKind; + std::map::const_iterator aFIt = myFeatureMap.begin(); + for (; aFIt != myFeatureMap.end() && aKind.empty(); ++aFIt) + if (aFIt->second == anEntID) + aKind = aFIt->first->getKind(); + std::map::const_iterator anAtIt = myAttributeMap.begin(); + for (; anAtIt != myAttributeMap.end() && aKind.empty(); ++anAtIt) + if (anAtIt->second == anEntID) + aKind = anAtIt->first->attributeType(); + + if (aKind == SketchPlugin_Line::ID()) { + Slvs_Entity aLine = myStorage->getEntity(anEntID); + fixLine(aLine); + } + else if (aKind == SketchPlugin_Arc::ID()) { + Slvs_Entity anArc = myStorage->getEntity(anEntID); + fixArc(anArc); + } + else if (aKind == SketchPlugin_Circle::ID()) { + Slvs_Entity aCirc = myStorage->getEntity(anEntID); + fixCircle(aCirc); + } + else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) { + fixPoint(anEntID); + } +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.h b/src/SketchSolver/SketchSolver_ConstraintMovement.h index dd2b0df74..dbec1b020 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.h +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.h @@ -38,9 +38,12 @@ protected: /// \param[out] theIsFullyMoved shows that the feature is moved, in other case only one point of the feature is shifted virtual void getAttributes(double& theValue, std::vector& theAttributes, bool& theIsFullyMoved); + /// \brief Fixed feature basing on its type + virtual void fixFeature(); + private: /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity - bool isMoved(std::shared_ptr thePoint, Slvs_hEntity theEntity); + bool isMoved(std::shared_ptr thePoint, const Slvs_Entity& theEntity); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp index 3f52e1992..ed8ae3712 100644 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp @@ -40,42 +40,72 @@ void SketchSolver_ConstraintRigid::process() fixFeature(); } +void SketchSolver_ConstraintRigid::update(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (theConstraint && theConstraint == myBaseConstraint && + theConstraint->getKind() == myBaseConstraint->getKind() && + checkAttributesChanged(theConstraint)) { + // remove previous constraint and set the given one + remove(myBaseConstraint); + myBaseConstraint = theConstraint; + process(); + } +} + +static void fixEntity(StoragePtr theStorage, const Slvs_hEntity& theEntID) +{ + Slvs_Entity anEntity = theStorage->getEntity(theEntID); + anEntity.group = SLVS_G_OUTOFGROUP; + theStorage->updateEntity(anEntity); + // move out of group all sub-entities + for (int i = 0; i < 4; ++i) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + fixEntity(theStorage, anEntity.point[i]); + // move out of group the radius of circle + if (anEntity.distance != SLVS_E_UNKNOWN) + fixEntity(theStorage, anEntity.distance); + // move out of group parameters + for (int i = 0; i < 4; ++i) + if (anEntity.param[i] != SLVS_E_UNKNOWN) { + Slvs_Param aParam = theStorage->getParameter(anEntity.param[i]); + aParam.group = SLVS_G_OUTOFGROUP; + theStorage->updateParameter(aParam); + } +} + void SketchSolver_ConstraintRigid::fixFeature() { - Slvs_hEntity anEntID; - if (!myFeatureMap.empty()) - anEntID = myFeatureMap.begin()->second; - else - anEntID = myAttributeMap.begin()->second; - //if (myStorage->isEntityFixed(anEntID, true)) { - // myErrorMsg = SketchSolver_Error::ALREADY_FIXED(); - // return; - //} - - std::string aKind; - if (!myFeatureMap.empty()) - aKind = myFeatureMap.begin()->first->getKind(); - else - aKind = myAttributeMap.begin()->first->attributeType(); + Slvs_hEntity anEntID = fixedEntity(); + if (anEntID != SLVS_E_UNKNOWN) + fixEntity(myStorage, anEntID); +} - if (aKind == SketchPlugin_Line::ID()) { - Slvs_Entity aLine = myStorage->getEntity(anEntID); - fixLine(aLine); - } - else if (aKind == SketchPlugin_Arc::ID()) { - Slvs_Entity anArc = myStorage->getEntity(anEntID); - fixArc(anArc); - } - else if (aKind == SketchPlugin_Circle::ID()) { - Slvs_Entity aCirc = myStorage->getEntity(anEntID); - fixCircle(aCirc); +Slvs_hEntity SketchSolver_ConstraintRigid::fixedEntity() const +{ + Slvs_hEntity anEntID = SLVS_E_UNKNOWN; + if (myBaseConstraint) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + std::map::const_iterator aFound = myFeatureMap.find(aFeature); + if (aFound != myFeatureMap.end()) + anEntID = aFound->second; + } else { + std::map::const_iterator aFound = myAttributeMap.find(aRefAttr->attr()); + if (aFound != myAttributeMap.end()) + anEntID = aFound->second; + } } - else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) { - fixPoint(anEntID); + else if (myBaseFeature) { + std::map::const_iterator aFound = myFeatureMap.find(myBaseFeature); + if (aFound != myFeatureMap.end()) + anEntID = aFound->second; } + return anEntID; } - void SketchSolver_ConstraintRigid::getAttributes( double& theValue, std::vector& theAttributes) @@ -116,38 +146,6 @@ void SketchSolver_ConstraintRigid::getAttributes( theAttributes.push_back(anEntityID); } -void SketchSolver_ConstraintRigid::adjustConstraint() -{ - if (myFeatureMap.empty() || ( - myFeatureMap.begin()->first->getKind() != SketchPlugin_Arc::ID() && - myFeatureMap.begin()->first->getKind() != SketchPlugin_Circle::ID())) - return; - FeaturePtr aFeature = myFeatureMap.begin()->first; - - // Search radius constraints and update them - Slvs_Constraint aConstraint; - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) { - aConstraint = myStorage->getConstraint(*aCIter); - if (aConstraint.type != SLVS_C_DIAMETER) - continue; - double aRadius = 0.0; - if (aFeature->getKind() == SketchPlugin_Arc::ID()) { - std::shared_ptr aCenter = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aStart = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - aRadius = aCenter->distance(aStart); - } else { - aRadius = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Circle::RADIUS_ID()))->value(); - } - - aConstraint.valA = aRadius * 2.0; - *aCIter = myStorage->updateConstraint(aConstraint); - } -} - bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint) { @@ -155,10 +153,19 @@ bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint) if (theConstraint && theConstraint != myBaseConstraint) return false; bool isFullyRemoved = true; + std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) + for (; aCIter != mySlvsConstraints.end(); ++aCIter) isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; + std::map::iterator aFIter = myFeatureMap.begin(); + for (; aFIter != myFeatureMap.end(); ++aFIter) + isFullyRemoved = myStorage->removeEntity(aFIter->second) && isFullyRemoved; + + std::map::iterator anAtIter = myAttributeMap.begin(); + for (; anAtIter != myAttributeMap.end(); ++anAtIter) + isFullyRemoved = myStorage->removeEntity(anAtIter->second) && isFullyRemoved; + if (isFullyRemoved) { myFeatureMap.clear(); myAttributeMap.clear(); @@ -169,10 +176,10 @@ bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint) return true; } -void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) +Slvs_hConstraint SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) { if (thePointID == SLVS_E_UNKNOWN) - return; + return SLVS_C_UNKNOWN; Slvs_Constraint aConstraint; Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; @@ -180,22 +187,23 @@ void SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) bool isForceUpdate = (isFixed && !myBaseConstraint && myStorage->isTemporary(aConstrID)); if (!isForceUpdate) { // create new constraint - if (isFixed) return; - aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), + if (isFixed) return aConstrID; + aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); aConstraint.h = myStorage->addConstraint(aConstraint); mySlvsConstraints.push_back(aConstraint.h); if (!myBaseConstraint) myStorage->addConstraintWhereDragged(aConstraint.h); } else { // update already existent constraint - if (!isFixed || aConstrID == SLVS_E_UNKNOWN || myBaseConstraint) - return; + if (!isFixed || aConstrID == SLVS_C_UNKNOWN || myBaseConstraint) + return SLVS_C_UNKNOWN; aConstraint = myStorage->getConstraint(aConstrID); aConstraint.ptA = thePointID; myStorage->addConstraint(aConstraint); if (!myBaseConstraint) myStorage->addConstraintWhereDragged(aConstraint.h); } + return aConstraint.h; } void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine) diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h index 22f4c6dd5..adac8c6a3 100644 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.h +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.h @@ -15,7 +15,10 @@ * \brief Stores data of Rigid (Fixed) constraint * * Rigid constraint may have NULL basic SketchPlugin constraint, - * because the Rigid constraint may be temporary for correct moving of objects + * because the Rigid constraint may be temporary for correct moving of objects. + * + * Rigid constraint does not create a constraint, but builds the entities in separate group, + * so they will not be moved while resolving the set of constraints. */ class SketchSolver_ConstraintRigid : public SketchSolver_Constraint { @@ -27,6 +30,9 @@ public: /// Creates temporary constraint based on feature SketchSolver_ConstraintRigid(FeaturePtr theFeature); + /// \brief Update constraint + virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); + /// \brief Tries to remove constraint /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); @@ -44,17 +50,16 @@ protected: /// \param[out] theAttributes list of attributes to be filled virtual void getAttributes(double& theValue, std::vector& theAttributes); - /// \brief This method is used in derived objects to check consistence of constraint. - /// E.g. the distance between line and point may be signed. - virtual void adjustConstraint(); - /// \brief Fixed feature basing on its type - void fixFeature(); + virtual void fixFeature(); /// \brief Fix given point - void fixPoint(const Slvs_hEntity& thePointID); + /// \return ID of the Fixed constraint + Slvs_hConstraint fixPoint(const Slvs_hEntity& thePointID); + + /// \brief Returns ID of fixed entity + Slvs_hEntity fixedEntity() const; -private: /// \brief Fixing line position (start and end points) void fixLine(const Slvs_Entity& theLine); /// \brief Fixing circle (center and radius) diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 5a9652fe6..9ad17d750 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -563,7 +563,8 @@ bool SketchSolver_Group::resolveConstraints() updateConstraints(); bool aResolved = false; - if (myStorage->isNeedToResolve() && !isEmpty()) { + bool isGroupEmpty = isEmpty(); + if (myStorage->isNeedToResolve() && !isGroupEmpty) { myConstrSolver.setGroupID(myID); myConstrSolver.calculateFailedConstraints(false); myStorage->initializeSolver(myConstrSolver); @@ -631,6 +632,16 @@ bool SketchSolver_Group::resolveConstraints() } aResolved = true; + } else if (!isGroupEmpty) { + myFeatureStorage->blockEvents(true); + // Check there are constraints Fixed. If they exist, update parameters by stored values + ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) + if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) { + aCIt->second->refresh(); + aResolved = true; + } + myFeatureStorage->blockEvents(false); } removeTemporaryConstraints(); myStorage->setNeedToResolve(false); diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 4ed2112e4..58cd67418 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -371,6 +371,14 @@ bool SketchSolver_Storage::isPointFixed( break; } + // Check whether one of coincident points is out-of-group + std::set::const_iterator aCoincIt = aCoincident.begin(); + for (; aCoincIt != aCoincident.end(); ++aCoincIt) { + Slvs_Entity aPoint = getEntity(*aCoincIt); + if (aPoint.group == SLVS_G_OUTOFGROUP) + return true; + } + // Search the Rigid constraint theFixed = SLVS_C_UNKNOWN; std::vector::const_iterator aConstrIter = myConstraints.begin(); diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index fb8e79eb2..bb270d77d 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -69,6 +69,9 @@ public: void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo); /// \brief Check the entity is used in constraints bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const; + /// \brief Returns maximal ID of entities in this storage + const Slvs_hEntity& entityMaxID() const + { return myEntityMaxID; } /// \brief Verifies the current point or another coincident one is fixed /// \param[in] thePointID entity to be checked fixed @@ -105,6 +108,9 @@ public: const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const; /// \brief Returns list of constraints of specified type std::list getConstraintsByType(int theConstraintType) const; + /// \brief Returns quantity of constraints in this storage + size_t nbConstraints() const + { return myConstraints.size(); } /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID); -- 2.30.2