From 0a0d72b1c81fba68ff81714b4273e5af260c3d83 Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 30 Mar 2017 09:00:34 +0300 Subject: [PATCH] Issue #1848: Redesign Sketcher mirrorEntities Generate error when cyclic dependency between original and mirrored entities has been detected --- .../SketchSolver_ConstraintMirror.cpp | 11 +-- src/SketchSolver/SketchSolver_Error.h | 8 ++ src/SketchSolver/SketchSolver_Group.cpp | 73 +++++++++++++++---- src/SketchSolver/SketchSolver_Group.h | 5 ++ src/SketchSolver/SketchSolver_msg_en.ts | 4 + 5 files changed, 79 insertions(+), 22 deletions(-) diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index 335997a2e..b338983ca 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -62,13 +62,6 @@ void SketchSolver_ConstraintMirror::getAttributes( myFeatures.insert(aFeature); } } - // add mirrored features to the list - aList = aMirroredRefList->list(); - for (anIt = aList.begin(); anIt != aList.end(); ++anIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); - if (aFeature) - myFeatures.insert(aFeature); - } } void SketchSolver_ConstraintMirror::process() @@ -118,6 +111,10 @@ void SketchSolver_ConstraintMirror::adjustConstraint() FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt); FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt); mirrorEntities(aMirrorLine, aBase, aMirrored); + + // update mirrored entity if it exists in the storage + if (myStorage->entity(aMirrored)) + myStorage->update(aMirrored); } } diff --git a/src/SketchSolver/SketchSolver_Error.h b/src/SketchSolver/SketchSolver_Error.h index 64e080045..a4fe89945 100644 --- a/src/SketchSolver/SketchSolver_Error.h +++ b/src/SketchSolver/SketchSolver_Error.h @@ -24,6 +24,14 @@ class SketchSolver_Error "To fix this, you can either undo your operation or remove a conflicting constraint."); return MY_ERROR_VALUE; } + /// Cyclic dependency of copied features with their originals + inline static const std::string& INFINITE_LOOP() + { + static const std::string MY_ERROR_VALUE( + "There is a circular reference between copied sketch entities and their originals. " + "To fix this, you can either undo your operation or remove wrong constraint."); + return MY_ERROR_VALUE; + } /// Constraints should use objects instead of features as attributes inline static const std::string& NEED_OBJECT_NOT_FEATURE() { diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 329f6f84c..26b960e2a 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -15,7 +15,10 @@ #include #include #include +#include #include +#include +#include static void sendMessage(const char* theMessageName) @@ -60,7 +63,8 @@ SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane) : mySketch(theWorkplane), myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN), myDOF(0), - myIsEventsBlocked(false) + myIsEventsBlocked(false), + myMultiConstraintUpdateStack(0) { mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver); myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver)); @@ -100,6 +104,9 @@ bool SketchSolver_Group::changeConstraint( } else myConstraints[theConstraint]->update(); + + // constraint is created/updated => reset stack of "multi" constraints updates + myMultiConstraintUpdateStack = 0; return true; } @@ -136,6 +143,16 @@ bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) // ============================================================================ bool SketchSolver_Group::resolveConstraints() { + // check the "Multi" constraints do not drop sketch into infinite loop + if (myMultiConstraintUpdateStack > 1) { + myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED; + // generate error message due to loop update of the sketch + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR()) + ->setValue(SketchSolver_Error::INFINITE_LOOP()); + sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints); + return false; + } + bool aResolved = false; bool isGroupEmpty = isEmpty() && myStorage->isEmpty(); if (myStorage->isNeedToResolve() && @@ -144,7 +161,7 @@ bool SketchSolver_Group::resolveConstraints() PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK; try { - if (!isGroupEmpty) + if (!isGroupEmpty && myMultiConstraintUpdateStack <= 1) aResult = mySketchSolver->solve(); } catch (...) { getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR()) @@ -163,19 +180,27 @@ bool SketchSolver_Group::resolveConstraints() aResult == PlaneGCSSolver_Solver::STATUS_EMPTYSET) { myStorage->setNeedToResolve(false); myStorage->refresh(); -//// updateMultiConstraints(myConstraints); -//// // multi-constraints updated some parameters, need to store them -//// if (myStorage->isNeedToResolve()) -//// resolveConstraints(); - if (myPrevResult != PlaneGCSSolver_Solver::STATUS_OK || - myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) { - getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); - std::set aConflicting = myConflictingConstraints; - myConflictingConstraints.clear(); - myPrevResult = PlaneGCSSolver_Solver::STATUS_OK; - // the error message should be changed before sending the message - sendMessage(EVENT_SOLVER_REPAIRED, aConflicting); + // additional check that copied entities used in Mirror and other "Multi" constraints + // is not connected with their originals by constraints. + myMultiConstraintUpdateStack += 1; + updateMultiConstraints(); + aResolved = true; + if (myStorage->isNeedToResolve()) + aResolved = resolveConstraints(); + + if (aResolved) { + myMultiConstraintUpdateStack -= 1; + + if (myPrevResult != PlaneGCSSolver_Solver::STATUS_OK || + myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) { + getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); + std::set aConflicting = myConflictingConstraints; + myConflictingConstraints.clear(); + myPrevResult = PlaneGCSSolver_Solver::STATUS_OK; + // the error message should be changed before sending the message + sendMessage(EVENT_SOLVER_REPAIRED, aConflicting); + } } // show degrees of freedom @@ -209,7 +234,6 @@ bool SketchSolver_Group::resolveConstraints() } } - aResolved = true; } else if (isGroupEmpty && isWorkplaneValid()) computeDoF(); removeTemporaryConstraints(); @@ -301,6 +325,9 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) for (; aCIter != myConstraints.end(); aCIter++) if (aCIter->first == theConstraint) { aCIter->second->remove(); // the constraint is not fully removed + + // constraint is removed => reset stack of "multi" constraints updates + myMultiConstraintUpdateStack = 0; break; } if (aCIter != myConstraints.end()) @@ -337,3 +364,19 @@ void SketchSolver_Group::blockEvents(bool isBlocked) myIsEventsBlocked = isBlocked; } + +// ============================================================================ +// Function: updateMultiConstraints +// Class: SketchSolver_Group +// Purpose: update multi constraints +// ============================================================================ +void SketchSolver_Group::updateMultiConstraints() +{ + ConstraintConstraintMap::iterator anIt = myConstraints.begin(); + for (; anIt != myConstraints.end(); ++anIt) { + if (anIt->first->getKind() == SketchPlugin_ConstraintMirror::ID() || + anIt->first->getKind() == SketchPlugin_MultiRotation::ID() || + anIt->first->getKind() == SketchPlugin_MultiTranslation::ID()) + anIt->second->update(); + } +} diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h index a5fb221ae..4db35d4fe 100644 --- a/src/SketchSolver/SketchSolver_Group.h +++ b/src/SketchSolver/SketchSolver_Group.h @@ -95,6 +95,9 @@ private: /// \brief Append given constraint to the group of temporary constraints void setTemporary(SolverConstraintPtr theConstraint); + /// \brief Update dependent (copied) features created by Mirror and other "Multi" constraints + void updateMultiConstraints(); + /// \brief Compute DoF of the sketch and set corresponding field void computeDoF(); @@ -113,6 +116,8 @@ private: int myDOF; ///< degrees of freedom of the current sketch bool myIsEventsBlocked; ///< shows the events are blocked for this group + + int myMultiConstraintUpdateStack; ///< depth of the stack updating "Multi" constraints }; typedef std::shared_ptr SketchGroupPtr; diff --git a/src/SketchSolver/SketchSolver_msg_en.ts b/src/SketchSolver/SketchSolver_msg_en.ts index 424f5d40f..f3b66c609 100755 --- a/src/SketchSolver/SketchSolver_msg_en.ts +++ b/src/SketchSolver/SketchSolver_msg_en.ts @@ -7,6 +7,10 @@ The constraint is conflicting with others. To fix this, you can either undo your operation or remove a conflicting constraint. The constraint is conflicting with others. To fix this, you can either undo your operation or remove a conflicting constraint. + + There is a circular reference between copied sketch entities and their originals. To fix this, you can either undo your operation or remove wrong constraint. + There is a circular reference between copied sketch entities and their originals. To fix this, you can either undo your operation or remove wrong constraint. + Caution: SolveSpace crash! Constraints are wrong Caution: SolveSpace crash! Constraints are wrong -- 2.39.2