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