From 34f533b0e1d3d6ddd45eb68cdfbc76c20ba94be8 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 21 Dec 2017 10:11:26 +0100 Subject: [PATCH] Sketcher: Block Constraint - Advanced redundant/conflict redundant handling =========================================================================== Block constraint is naturally redundant/conflicting with almost any other constraint applied to an edge (certainly with constraints operating only on that element). As such, a block constraint will have very little applicability in absence of a way to handle this redundancy/conflicting. For example, in the case of a BSpline all its internal geometry (construction circles on poles and its constraints) would have to be removed before locking. This would mean that it is not possible to define the BSpline shape and then block it, as when removing the internal geometry the shape would be lost. In other cases, like temporally blocking to avoid that a part of the sketch moves while performing some operation with the idea of afterwards unblocking it, it would mean removing all constraints, to add the block constraint, then perform the action, then remove the block constraint and manually constraint it again. Handling this situation in a user expected way means ignoring certain constraints (those causing the redundancy/conflicting), so that the solver is not aware of them and does not complain. However, generally ignoring those constraints has a negative effect, in that constraints applied by the user on already blocked geometry, or constraints that otherwise lead to a conflicting or redundant situation as a consequence of actions (further constraining) after the Block constrain is applied are ignored, thereby not properly informing the user of this situation, which is undesirable. This new mechanism takes account on the position of the constraints relative to the involved blocked constraint(s). As such, redundant/conflicting constraints that were added before the Block constraint are ignored, whereas those constraints that lead to a redundant/conflicting situation and added AFTER the block constraint was already in place, those are not ignored and are reported accordingly. --- src/Mod/Sketcher/App/Sketch.cpp | 120 +++++++++++++++++++++++++++++--- src/Mod/Sketcher/App/Sketch.h | 4 +- 2 files changed, 113 insertions(+), 11 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 527cf6eb4c..0e78b50940 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -128,10 +128,11 @@ int Sketch::setUpSketch(const std::vector &GeoList, for (int i=int(GeoList.size())-extGeoCount; i < int(GeoList.size()); i++) extGeoList.push_back(GeoList[i]); - std::vector blockedGeometry(intGeoList.size(),false); + std::vector blockedGeometry(intGeoList.size(),false); // these geometries are blocked, frozen and sent as fixed parameters to the solver + std::vector unenforceableConstraints(ConstraintList.size(),false); // these constraints are unenforceable due to a Blocked constraint if(!intGeoList.empty()) - getBlockedGeometry(blockedGeometry,ConstraintList); + getBlockedGeometry(blockedGeometry, unenforceableConstraints, ConstraintList); addGeometry(intGeoList,blockedGeometry); int extStart=Geoms.size(); @@ -142,7 +143,7 @@ int Sketch::setUpSketch(const std::vector &GeoList, // The Geoms list might be empty after an undo/redo if (!Geoms.empty()) { - addConstraints(ConstraintList); + addConstraints(ConstraintList,unenforceableConstraints); } GCSsys.clearByTag(-1); GCSsys.declareUnknowns(Parameters); @@ -1322,22 +1323,121 @@ int Sketch::addConstraints(const std::vector &ConstraintList) int rtn = -1; for (std::vector::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it) - rtn = addConstraint (*it); + rtn = addConstraint (*it); return rtn; } -void Sketch::getBlockedGeometry(std::vector & blockedGeometry, const std::vector &ConstraintList) +int Sketch::addConstraints(const std::vector &ConstraintList, std::vector &unenforceableConstraints) { + int rtn = -1; - for (std::vector::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it) { - if((*it)->Type == Blocked) { - int geoid = (*it)->First; + int cid = 0; + for (std::vector::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it,++cid) { + if (!unenforceableConstraints[cid] && (*it)->Type != Blocked) { + rtn = addConstraint (*it); + } + else { + ++ConstraintsCounter; // For correct solver redundant reporting + } + + } - if(geoid>=0 && geoid & blockedGeometry, std::vector & unenforceableConstraints, const std::vector &ConstraintList) +{ + std::vector internalAlignmentConstraintIndex; + std::vector internalAlignmentgeo; + + std::vector geo2blockingconstraintindex(blockedGeometry.size(),-1); + + // Detect Blocked and internal constraints + int i = 0; + for (std::vector::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it,++i) { + switch((*it)->Type) { + case Blocked: + { + int geoid = (*it)->First; + + if(geoid>=0 && geoid::iterator it = internalAlignmentConstraintIndex.begin(); it != internalAlignmentConstraintIndex.end() ; it++) { + if ( blockedGeometry[ConstraintList[(*it)]->Second] ) { + blockedGeometry[ConstraintList[(*it)]->First] = true; + // asociated geometry gets the same blocking constraint index as the blocked element + geo2blockingconstraintindex[ConstraintList[(*it)]->First]= geo2blockingconstraintindex[ConstraintList[(*it)]->Second]; + internalAlignmentgeo.push_back(ConstraintList[(*it)]->First); + unenforceableConstraints[(*it)]= true; + } + } + + i = 0; + for (std::vector::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it,++i) { + if((*it)->isDriving) { + // additionally any further constraint on auxiliary elements linked via Internal Alignment are also uneforceable. + for(std::vector::iterator itg = internalAlignmentgeo.begin(); itg != internalAlignmentgeo.end() ; itg++) { + if( (*it)->First==*itg || (*it)->Second==*itg || (*it)->Third==*itg ) { + unenforceableConstraints[i]= true; + } + } + // IMPORTANT NOTE: + // The rest of the ignoring of redundant/conflicting applies to constraints introduced before the blocking constraint only + // Constraints introduced after the block will not be ignored and will lead to redundancy/conflicting status as per normal + // solver behaviour + + // further, any constraint taking only one element, which is blocked is also unenforceable + if((*it)->Second==Constraint::GeoUndef && (*it)->Third==Constraint::GeoUndef) { + if (blockedGeometry[(*it)->First] && i < geo2blockingconstraintindex[(*it)->First]) { + unenforceableConstraints[i]= true; + } + } + // further any constraint on only two elements where both elements are blocked or one is blocked and the other is an axis or external + // provided that the constraints precede the last block constraint. + else if((*it)->Third==Constraint::GeoUndef) { + if ( ((*it)->First>=0 && (*it)->Second>=0 && blockedGeometry[(*it)->First] && blockedGeometry[(*it)->Second] && + (i < geo2blockingconstraintindex[(*it)->First] || i < geo2blockingconstraintindex[(*it)->Second])) || + ((*it)->First<0 && (*it)->Second>=0 && blockedGeometry[(*it)->Second] && i < geo2blockingconstraintindex[(*it)->Second]) || + ((*it)->First>=0 && (*it)->Second<0 && blockedGeometry[(*it)->First] && i < geo2blockingconstraintindex[(*it)->First]) ){ + unenforceableConstraints[i]= true; + } + } + // further any constraint on three elements where the three of them are blocked, or two are blocked and the other is an axis or external geo + // or any constraint on three elements where one is blocked and the other two are axis or external geo, provided that the constraints precede + // the last block constraint. + else { + if( ((*it)->First>=0 && (*it)->Second>=0 && (*it)->Third>=0 && + blockedGeometry[(*it)->First] && blockedGeometry[(*it)->Second] && blockedGeometry[(*it)->Third] && + (i < geo2blockingconstraintindex[(*it)->First] || i < geo2blockingconstraintindex[(*it)->Second] || i < geo2blockingconstraintindex[(*it)->Third])) || + ((*it)->First<0 && (*it)->Second>=0 && (*it)->Third>=0 && blockedGeometry[(*it)->Second] && blockedGeometry[(*it)->Third] && + (i < geo2blockingconstraintindex[(*it)->Second] || i < geo2blockingconstraintindex[(*it)->Third])) || + ((*it)->First>=0 && (*it)->Second<0 && (*it)->Third>=0 && blockedGeometry[(*it)->First] && blockedGeometry[(*it)->Third] && + (i < geo2blockingconstraintindex[(*it)->First] || i < geo2blockingconstraintindex[(*it)->Third])) || + ((*it)->First>=0 && (*it)->Second>=0 && (*it)->Third<0 && blockedGeometry[(*it)->First] && blockedGeometry[(*it)->Second] && + (i < geo2blockingconstraintindex[(*it)->First] || i < geo2blockingconstraintindex[(*it)->Second])) || + ((*it)->First>=0 && (*it)->Second<0 && (*it)->Third<0 && blockedGeometry[(*it)->First] && i < geo2blockingconstraintindex[(*it)->First]) || + ((*it)->First<0 && (*it)->Second>=0 && (*it)->Third<0 && blockedGeometry[(*it)->Second] && i < geo2blockingconstraintindex[(*it)->Second]) || + ((*it)->First<0 && (*it)->Second<0 && (*it)->Third>=0 && blockedGeometry[(*it)->Third] && i < geo2blockingconstraintindex[(*it)->Third]) ) { + + unenforceableConstraints[i]= true; + } + } + } + } } int Sketch::addCoordinateXConstraint(int geoId, PointPos pos, double * value) diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 80a82055f0..41dd67fbca 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -81,7 +81,7 @@ public: /// add unspecified geometry, where each element's "fixed" status is given by the blockedGeometry array int addGeometry(const std::vector &geo, std::vector &blockedGeometry); /// get boolean list indicating whether the geometry is to be blocked or not - void getBlockedGeometry(std::vector & blockedGeometry, const std::vector &ConstraintList); + void getBlockedGeometry(std::vector & blockedGeometry, std::vector & unenforceableConstraints, const std::vector &ConstraintList); /// returns the actual geometry std::vector extractGeometry(bool withConstructionElements=true, bool withExternalElements=false) const; @@ -149,6 +149,8 @@ public: //@{ /// add all constraints in the list int addConstraints(const std::vector &ConstraintList); + /// add all constraints in the list, provided that are enforceable + int addConstraints(const std::vector &ConstraintList, std::vector & unenforceableConstraints); /// add one constraint to the sketch int addConstraint(const Constraint *constraint);