From 87699ea18de126b5bd03642b35e6a23a9c0c2c3f Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 15 Dec 2020 06:40:50 +0100 Subject: [PATCH] Sketcher: Sketch.cpp - use SolverGeometryExtension as mechanism to convey dependent parameter information ========================================================================================================= Former mechanism with hasDependentParameters is not flexible enough for the new kind of information. This commit further enhances the calculation of dependent parameters and dependent parameter groups by caching the parameter-geoelement (GeoId, PointPos) relationship during geometry creation. This commit provides traditional information whether a parameter is dependent via SolverGeometryExtension. New enhanced information about groups of dependent parameters are available via the Sketch API. --- src/Mod/Sketcher/App/Sketch.cpp | 294 ++++++++++++++++++++++---------- src/Mod/Sketcher/App/Sketch.h | 12 +- 2 files changed, 214 insertions(+), 92 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 308511440b..6ff57bde8b 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -55,10 +55,13 @@ #include #include -#include "Sketch.h" #include "Constraint.h" #include "GeometryFacade.h" +#include "SolverGeometryExtension.h" + +#include "Sketch.h" + using namespace Sketcher; using namespace Base; @@ -105,6 +108,9 @@ void Sketch::clear(void) if (*it) delete *it; FixParameters.clear(); + param2geoelement.clear(); + pDependencyGroups.clear(); + // deleting the geometry copied into this sketch for (std::vector::iterator it = Geoms.begin(); it != Geoms.end(); ++it) if (it->geo) delete it->geo; @@ -159,7 +165,7 @@ int Sketch::setUpSketch(const std::vector &GeoList, GCSsys.initSolution(defaultSolverRedundant); GCSsys.getConflicting(Conflicting); GCSsys.getRedundant(Redundant); - GCSsys.getDependentParams(pconstraintplistOut); + GCSsys.getDependentParams(pDependentParametersList); calculateDependentParametersElements(); @@ -179,106 +185,114 @@ void Sketch::clearTemporaryConstraints(void) void Sketch::calculateDependentParametersElements(void) { + // initialize solve extensions to a know state for(auto geo : Geoms) { - std::vector ownparams; - GCS::Curve * pCurve = nullptr; - switch(geo.type) { - case Point: - { - GCS::Point & point = Points[geo.startPointId]; - for(auto param : pconstraintplistOut) { - if (param == point.x || param == point.y) { - point.hasDependentParameters = true; - break; - } - } - } - break; - case Line: - { - GCS::Line & line = Lines[geo.index]; - line.PushOwnParams(ownparams); - pCurve = &line; + if(!geo.geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) + geo.geo->setExtension(std::make_unique()); + auto solvext = std::static_pointer_cast( + geo.geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock()); + + if(GCSsys.isEmptyDiagnoseMatrix()) + solvext->init(SolverGeometryExtension::Dependent); + else + solvext->init(SolverGeometryExtension::Independent); + } + + for(auto param : pDependentParametersList) { + + //auto element = param2geoelement.at(param); + auto element = param2geoelement.find(param); + + if (element != param2geoelement.end()) { + auto solvext = std::static_pointer_cast( + Geoms[element->second.first].geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock()); + + switch(element->second.second) { + case none: + solvext->setEdge(SolverGeometryExtension::Dependent); + break; + case start: + solvext->setStart(SolverGeometryExtension::Dependent); + break; + case end: + solvext->setEnd(SolverGeometryExtension::Dependent); + break; + case mid: + solvext->setMid(SolverGeometryExtension::Dependent); + break; } - break; - case Arc: - { - GCS::Arc & arc = Arcs[geo.index]; - arc.PushOwnParams(ownparams); - pCurve = &arc; - } - break; - case Circle: - { - GCS::Circle & c = Circles[geo.index]; - c.PushOwnParams(ownparams); - pCurve = &c; - } - break; - case Ellipse: - { - GCS::Ellipse & e = Ellipses[geo.index]; - e.PushOwnParams(ownparams); - pCurve = &e; - } - break; - case ArcOfEllipse: - { - GCS::ArcOfEllipse & aoe = ArcsOfEllipse[geo.index]; - aoe.PushOwnParams(ownparams); - pCurve = &aoe; - } - break; - case ArcOfHyperbola: - { - GCS::ArcOfHyperbola & aoh = ArcsOfHyperbola[geo.index]; - aoh.PushOwnParams(ownparams); - pCurve = &aoh; - } - break; - case ArcOfParabola: - { - GCS::ArcOfParabola & aop = ArcsOfParabola[geo.index]; - aop.PushOwnParams(ownparams); - pCurve = &aop; - } - break; - case BSpline: - { - GCS::BSpline & bsp = BSplines[geo.index]; - bsp.PushOwnParams(ownparams); - pCurve = &bsp; - } - break; - case None: - break; + } - // Points (this is single point elements, not vertices of other elements) are not derived from Curve - if(geo.type != Point && geo.type != None) { - for(auto param : pconstraintplistOut) { - for(auto ownparam : ownparams) { - if (param == ownparam) { - pCurve->hasDependentParameters = true; - break; - } - } + } + + std::vector < std::set < double*>> groups; + GCSsys.getDependentParamsGroups(groups); + + pDependencyGroups.resize(groups.size()); + + // translate parameters into elements (Geoid, PointPos) + for(size_t i = 0; i < groups.size(); i++) { + for(size_t j = 0; j < groups[i].size(); j++) { + + auto element = param2geoelement.find(*std::next(groups[i].begin(), j)); + + if (element != param2geoelement.end()) { + pDependencyGroups[i].insert(element->second); } } } - // Points are the only element that defines other elements, so these points (as opposed to those points - // above which are just GeomPoints), have to be handled separately. - for(auto & point : Points) { - for(auto param : pconstraintplistOut) { - if (param == point.x || param == point.y) { - point.hasDependentParameters = true; - break; + + // check if groups have a common element, if yes merge the groups + auto havecommonelement = [] ( std::set < std::pair< int, Sketcher::PointPos>>::iterator begin1, + std::set < std::pair< int, Sketcher::PointPos>>::iterator end1, + std::set < std::pair< int, Sketcher::PointPos>>::iterator begin2, + std::set < std::pair< int, Sketcher::PointPos>>::iterator end2) { + + while (begin1 != end1 && begin2 != end2) { + if (*begin1 < *begin2) + ++begin1; + else if (*begin2 < *begin1) + ++begin2; + else + return true; + } + + return false; + }; + + if(pDependencyGroups.size() > 1) { // only if there is more than 1 group + size_t endcount = pDependencyGroups.size()-1; + + for(size_t i=0; i < endcount; i++) { + if(havecommonelement(pDependencyGroups[i].begin(), pDependencyGroups[i].end(), pDependencyGroups[i+1].begin(), pDependencyGroups[i+1].end())){ + pDependencyGroups[i].insert(pDependencyGroups[i+1].begin(), pDependencyGroups[i+1].end()); + pDependencyGroups.erase(pDependencyGroups.begin()+i+1); + endcount--; } } } } +std::set < std::pair< int, Sketcher::PointPos>> Sketch::getDependencyGroup(int geoId, PointPos pos) const +{ + geoId = checkGeoId(geoId); + + std::set < std::pair< int, Sketcher::PointPos>> group; + + auto key = std::make_pair(geoId, pos); + + for( auto & set : pDependencyGroups) { + if (set.find(key) != set.end()) { + group = set; + break; + } + } + + return group; +} + int Sketch::resetSolver() { clearTemporaryConstraints(); @@ -287,7 +301,7 @@ int Sketch::resetSolver() GCSsys.initSolution(defaultSolverRedundant); GCSsys.getConflicting(Conflicting); GCSsys.getRedundant(Redundant); - GCSsys.getDependentParams(pconstraintplistOut); + GCSsys.getDependentParams(pDependentParametersList); calculateDependentParametersElements(); @@ -422,6 +436,11 @@ int Sketch::addPoint(const Part::GeomPoint &point, bool fixed) // store complete set Geoms.push_back(def); + if(!fixed) { + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -476,6 +495,13 @@ int Sketch::addLineSegment(const Part::GeomLineSegment &lineSegment, bool fixed) // store complete set Geoms.push_back(def); + if(!fixed) { + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -547,6 +573,18 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed) if (!fixed) GCSsys.addConstraintArcRules(a); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -635,6 +673,20 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f if (!fixed) GCSsys.addConstraintArcOfEllipseRules(a); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -721,6 +773,21 @@ int Sketch::addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, if (!fixed) GCSsys.addConstraintArcOfHyperbolaRules(a); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + + // return the position of the newly added geometry return Geoms.size()-1; } @@ -797,6 +864,19 @@ int Sketch::addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, boo if (!fixed) GCSsys.addConstraintArcOfParabolaRules(a); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -859,13 +939,23 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) p.y = params[params.size()-1]; spoles.push_back(p); + + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } } std::vector sweights; for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it) { - params.push_back(new double( (*it) )); + auto r = new double( (*it) ); + params.push_back(r); sweights.push_back(params[params.size()-1]); + + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } } std::vector sknots; @@ -944,6 +1034,14 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) GCSsys.addConstraintP2PCoincident(*(bs.poles.end()-1),bs.end); } + if(!fixed) { + // Note: Poles and weight parameters are emplaced above + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -987,6 +1085,12 @@ int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed) // store complete set Geoms.push_back(def); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + // return the position of the newly added geometry return Geoms.size()-1; } @@ -1045,6 +1149,14 @@ int Sketch::addEllipse(const Part::GeomEllipse &elip, bool fixed) // store complete set Geoms.push_back(def); + if(!fixed) { + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none)); + } + // return the position of the newly added geometry return Geoms.size()-1; } diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 7ecd0a0f00..c1beac27b8 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -108,6 +108,11 @@ public: inline const std::vector &getRedundant(void) const { return Redundant; } inline bool hasMalformedConstraints(void) const { return malformedConstraints; } +public: + std::set < std::pair< int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) const; + + +public: /** set the datum of a distance or angle constraint to a certain value and solve * This can cause the solving to fail! @@ -411,7 +416,12 @@ protected: std::vector Conflicting; std::vector Redundant; - std::vector pconstraintplistOut; + std::vector pDependentParametersList; + + std::vector < std::set < std::pair< int, Sketcher::PointPos>>> pDependencyGroups; + + // this map is intended to convert a parameter (double *) into a GeoId/PointPos pair + std::map> param2geoelement; // solving parameters std::vector Parameters; // with memory allocation