From 64df620407209c860f4023428f088baf94772b4e Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Mon, 4 Jan 2021 08:59:18 +0100 Subject: [PATCH] Sketcher: Retrieve 1-based list of malformed constraints from solver --- src/Mod/Sketcher/App/Sketch.cpp | 14 ++-- src/Mod/Sketcher/App/Sketch.h | 6 +- src/Mod/Sketcher/App/SketchObject.cpp | 100 +++++++++++++++----------- src/Mod/Sketcher/App/SketchObject.h | 16 +++++ 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 87569bcf53..c73fe03567 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -76,7 +76,6 @@ Sketch::Sketch() , RecalculateInitialSolutionWhileMovingPoint(false) , GCSsys(), ConstraintsCounter(0) , isInitMove(false), isFine(true), moveStep(0) - , malformedConstraints(false) , defaultSolver(GCS::DogLeg) , defaultSolverRedundant(GCS::DogLeg) , debugMode(GCS::Minimal) @@ -127,7 +126,8 @@ void Sketch::clear(void) isInitMove = false; ConstraintsCounter = 0; Conflicting.clear(); - malformedConstraints = false; + Redundant.clear(); + MalformedConstraints.clear(); } bool Sketch::analyseBlockedGeometry( const std::vector &internalGeoList, @@ -1913,8 +1913,9 @@ int Sketch::addConstraints(const std::vector &ConstraintList) rtn = addConstraint (*it); if(rtn == -1) { - Base::Console().Error("Sketcher constraint number %d is malformed!\n",cid); - malformedConstraints = true; + int humanconstraintid = cid + 1; + Base::Console().Error("Sketcher constraint number %d is malformed!\n",humanconstraintid); + MalformedConstraints.push_back(humanconstraintid); } } @@ -1932,8 +1933,9 @@ int Sketch::addConstraints(const std::vector &ConstraintList, rtn = addConstraint (*it); if(rtn == -1) { - Base::Console().Error("Sketcher constraint number %d is malformed!\n",cid); - malformedConstraints = true; + int humanconstraintid = cid + 1; + Base::Console().Error("Sketcher constraint number %d is malformed!\n",humanconstraintid); + MalformedConstraints.push_back(humanconstraintid); } } else { diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index f23150afda..252e602a7d 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -106,7 +106,8 @@ public: inline float getSolveTime() const { return SolveTime; } - inline bool hasMalformedConstraints(void) const { return malformedConstraints; } + inline bool hasMalformedConstraints(void) const { return !MalformedConstraints.empty(); } + inline const std::vector &getMalformedConstraints(void) const { return MalformedConstraints; } public: std::set < std::pair< int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) const; @@ -425,6 +426,7 @@ protected: int ConstraintsCounter; std::vector Conflicting; std::vector Redundant; + std::vector MalformedConstraints; std::vector pDependentParametersList; @@ -453,8 +455,6 @@ protected: Base::Vector3d initToPoint; double moveStep; - bool malformedConstraints; - public: GCS::Algorithm defaultSolver; GCS::Algorithm defaultSolverRedundant; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index ef0efeecb8..9b00d83814 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -133,6 +133,7 @@ SketchObject::SketchObject() lastDoF=0; lastHasConflict=false; lastHasRedundancies=false; + lastHasMalformedConstraints=false; lastSolverStatus=0; lastSolveTime=0; @@ -213,12 +214,14 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) appendRedundantMsg(lastRedundant, msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } + else if (err == -5) { + std::string msg="Sketch with malformed constraints\n"; + appendMalformedConstraintsMsg(lastMalformedConstraints, msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } else if (err == -1) { // Solver failed return new App::DocumentObjectExecReturn("Solving the sketch failed",this); } - else if (solvedSketch.hasMalformedConstraints()) { - return new App::DocumentObjectExecReturn("Sketch has malformed constraints"); - } // this is not necessary for sketch representation in edit mode, unless we want to trigger an update of // the objects that depend on this sketch (like pads) @@ -237,6 +240,16 @@ int SketchObject::hasConflicts(void) const return 0; } +void SketchObject::retrieveSolverDiagnostics() +{ + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastHasMalformedConstraints = solvedSketch.hasMalformedConstraints(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + lastMalformedConstraints=solvedSketch.getMalformedConstraints(); +} + int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) { Base::StateLocker lock(managedoperation, true); // no need to check input data validity as this is an sketchobject managed operation. @@ -264,10 +277,8 @@ int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) solverNeedsUpdate=false; - lastHasConflict = solvedSketch.hasConflicts(); - lastHasRedundancies = solvedSketch.hasRedundancies(); - lastConflicting=solvedSketch.getConflicting(); - lastRedundant=solvedSketch.getRedundant(); + retrieveSolverDiagnostics(); + lastSolveTime=0.0; lastSolverStatus=GCS::Failed; // Failure is default for notifying the user unless otherwise proven @@ -288,6 +299,9 @@ int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) // The situation is exactly the same as in the over-constrained situation. err = -3; } + else if (lastHasMalformedConstraints) { + err = -5; + } else { lastSolverStatus=solvedSketch.solve(); if (lastSolverStatus != 0){ // solving @@ -295,7 +309,7 @@ int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) } } - if(solvedSketch.hasMalformedConstraints()) { + if(lastHasMalformedConstraints) { Base::Console().Error("Sketch %s has malformed constraints!\n",this->getNameInDocument()); } @@ -680,12 +694,9 @@ int SketchObject::setUpSketch() lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); - lastHasConflict = solvedSketch.hasConflicts(); - lastHasRedundancies = solvedSketch.hasRedundancies(); - lastConflicting=solvedSketch.getConflicting(); - lastRedundant=solvedSketch.getRedundant(); + retrieveSolverDiagnostics(); - if(lastHasRedundancies || lastDoF < 0 || lastHasConflict) + if(lastHasRedundancies || lastDoF < 0 || lastHasConflict || lastHasMalformedConstraints) Constraints.touch(); return lastDoF; @@ -708,10 +719,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); - lastHasConflict = solvedSketch.hasConflicts(); - lastHasRedundancies = solvedSketch.hasRedundancies(); - lastConflicting=solvedSketch.getConflicting(); - lastRedundant=solvedSketch.getRedundant(); + retrieveSolverDiagnostics(); solverNeedsUpdate=false; } @@ -7097,40 +7105,50 @@ bool SketchObject::arePointsCoincident(int GeoId1, PointPos PosId1, } void SketchObject::appendConflictMsg(const std::vector &conflicting, std::string &msg) +{ + appendConstraintsMsg(conflicting, + "Please remove the following conflicting constraint:\n", + "Please remove at least one of the following conflicting constraints:\n", + msg); +} + +void SketchObject::appendRedundantMsg(const std::vector &redundant, std::string &msg) +{ + appendConstraintsMsg(redundant, + "Please remove the following redundant constraint:", + "Please remove the following redundant constraints:", + msg); +} + +void SketchObject::appendMalformedConstraintsMsg(const std::vector &malformed, std::string &msg) +{ + appendConstraintsMsg(malformed, + "Please remove the following malformed constraint:", + "Please remove the following malformed constraints:", + msg); +} + +void SketchObject::appendConstraintsMsg(const std::vector &vector, + const std::string &singularmsg, + const std::string &pluralmsg, + std::string &msg) { std::stringstream ss; if (msg.length() > 0) ss << msg; - if (conflicting.size() > 0) { - if (conflicting.size() == 1) - ss << "Please remove the following constraint:\n"; + if (vector.size() > 0) { + if (vector.size() == 1) + ss << singularmsg << std::endl; else - ss << "Please remove at least one of the following constraints:\n"; - ss << conflicting[0]; - for (unsigned int i=1; i < conflicting.size(); i++) - ss << ", " << conflicting[i]; + ss << pluralmsg; + ss << vector[0] << std::endl; + for (unsigned int i=1; i < vector.size(); i++) + ss << ", " << vector[i]; ss << "\n"; } msg = ss.str(); } -void SketchObject::appendRedundantMsg(const std::vector &redundant, std::string &msg) -{ - std::stringstream ss; - if (msg.length() > 0) - ss << msg; - if (redundant.size() > 0) { - if (redundant.size() == 1) - ss << "Please remove the following redundant constraint:\n"; - else - ss << "Please remove the following redundant constraints:\n"; - ss << redundant[0]; - for (unsigned int i=1; i < redundant.size(); i++) - ss << ", " << redundant[i]; - ss << "\n"; - } - msg = ss.str(); -} void SketchObject::getGeometryWithDependentParameters(std::vector>& geometrymap) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 9bf3aecd36..2d595d5b26 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -306,6 +306,8 @@ public: static void appendConflictMsg(const std::vector &conflicting, std::string &msg); /// generates a warning message about redundant constraints and appends it to the given message static void appendRedundantMsg(const std::vector &redundant, std::string &msg); + /// generates a warning message about malformed constraints and appends it to the given message + static void appendMalformedConstraintsMsg(const std::vector &malformed, std::string &msg); double calculateAngleViaPoint(int geoId1, int geoId2, double px, double py); bool isPointOnCurve(int geoIdCurve, double px, double py); @@ -346,6 +348,8 @@ public: inline bool getLastHasConflicts() const {return lastHasConflict;} /// gets HasRedundancies status of last solver execution inline bool getLastHasRedundancies() const {return lastHasRedundancies;} + /// gets HasMalformedConstraints status of last solver execution + inline bool getLastHasMalformedConstraints() const {return lastHasMalformedConstraints;} /// gets solver status of last solver execution inline int getLastSolverStatus() const {return lastSolverStatus;} /// gets solver SolveTime of last solver execution @@ -354,6 +358,8 @@ public: inline const std::vector &getLastConflicting(void) const { return lastConflicting; } /// gets the redundant constraints of last solver execution inline const std::vector &getLastRedundant(void) const { return lastRedundant; } + /// gets the redundant constraints of last solver execution + inline const std::vector &getLastMalformedConstraints(void) const { return lastMalformedConstraints; } public: /* Solver exposed interface */ /// gets the solved sketch as a reference @@ -476,6 +482,14 @@ protected: // migration functions void migrateSketch(void); + static void appendConstraintsMsg(const std::vector &vector, + const std::string & singularmsg, + const std::string & pluralmsg, + std::string &msg); + + // retrieves redundant, conflicting and malformed constraint information from the solver + void retrieveSolverDiagnostics(); + private: /// Flag to allow external geometry from other bodies than the one this sketch belongs to bool allowOtherBody; @@ -498,11 +512,13 @@ private: int lastDoF; bool lastHasConflict; bool lastHasRedundancies; + bool lastHasMalformedConstraints; int lastSolverStatus; float lastSolveTime; std::vector lastConflicting; std::vector lastRedundant; + std::vector lastMalformedConstraints; boost::signals2::scoped_connection constraintsRenamedConn; boost::signals2::scoped_connection constraintsRemovedConn;