From ad6576d385c2372e18aa5c0a06369950761e3403 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Mon, 2 May 2022 20:19:02 +0200 Subject: [PATCH] Sketcher: SolverGeometryExtension and sketch parameter information improvements =============================================================================== * SolverGeometryExtension is extended to: - Enable to determine whether the x or the y of a point is a dependent or independent parameter - Extend SolverExtension to provide information on individual edge parameters - Convenience access to DoF status * Sketch (solver interface) is extended to store geometry parameter dependency state, for these reasons: Geometry and Constraint solver information is generated when performing a full solve() [QR decomposition + minimization(e.g. DogLeg)]. Constraint information remains in the sketch object (not SketchObject, but sketch), which is then retrieved by SketchObject. Geometry information is incorporated to the deep copy of Geometry that the sketch object comprises. However, this information is only available outside the sketch object, if the Geometry property of SketchObject is assigned. This is always the situation after a successful full solve. However, it is not the case in a successful temporary minimal diagnosis (here succesful relates to conflicting/redundant constraints and convergence). The lightweight solution is to keep a (shallow) copy of the SolverGeometryExtensions (shared pointer) to be retrieved by GeoId, which is what is provided. --- src/Mod/Sketcher/App/Sketch.cpp | 170 +++++++----- src/Mod/Sketcher/App/Sketch.h | 12 +- .../Sketcher/App/SolverGeometryExtension.cpp | 101 ++++++- .../Sketcher/App/SolverGeometryExtension.h | 259 ++++++++++++++++-- 4 files changed, 446 insertions(+), 96 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 442a0ea127..7e548ec499 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -113,6 +113,7 @@ void Sketch::clear(void) param2geoelement.clear(); pDependencyGroups.clear(); + solverExtensions.clear(); // deleting the geometry copied into this sketch for (std::vector::iterator it = Geoms.begin(); it != Geoms.end(); ++it) @@ -378,7 +379,7 @@ bool Sketch::analyseBlockedConstraintDependentParameters(std::vector &block if (element != param2geoelement.end()) { - auto blockable = std::find(blockedGeoIds.begin(),blockedGeoIds.end(),element->second.first); + auto blockable = std::find(blockedGeoIds.begin(),blockedGeoIds.end(),std::get<0>(element->second)); if( blockable != blockedGeoIds.end()) { // This dependent parameter group contains at least one parameter that should be blocked, so added to the blockable list. @@ -432,6 +433,9 @@ void Sketch::clearTemporaryConstraints(void) void Sketch::calculateDependentParametersElements(void) { // initialize solve extensions to a know state + solverExtensions.resize(Geoms.size()); + + int i = 0; for(auto geo : Geoms) { if(!geo.geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) @@ -444,6 +448,9 @@ void Sketch::calculateDependentParametersElements(void) solvext->init(SolverGeometryExtension::Dependent); else solvext->init(SolverGeometryExtension::Independent); + + solverExtensions[i] = solvext; + i++; } for(auto param : pDependentParametersList) { @@ -452,24 +459,36 @@ void Sketch::calculateDependentParametersElements(void) auto element = param2geoelement.find(param); if (element != param2geoelement.end()) { + auto geoid = std::get<0>(element->second); + auto geopos = std::get<1>(element->second); auto solvext = std::static_pointer_cast( - Geoms[element->second.first].geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock()); + Geoms[geoid].geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock()); - switch(element->second.second) { + auto index = std::get<2>(element->second); + + switch(geopos) { case PointPos::none: - solvext->setEdge(SolverGeometryExtension::Dependent); + solvext->setEdge(index, SolverGeometryExtension::Dependent); break; case PointPos::start: - solvext->setStart(SolverGeometryExtension::Dependent); + if(index == 0) + solvext->setStartx(SolverGeometryExtension::Dependent); + else + solvext->setStarty(SolverGeometryExtension::Dependent); break; case PointPos::end: - solvext->setEnd(SolverGeometryExtension::Dependent); + if(index == 0) + solvext->setEndx(SolverGeometryExtension::Dependent); + else + solvext->setEndy(SolverGeometryExtension::Dependent); break; case PointPos::mid: - solvext->setMid(SolverGeometryExtension::Dependent); + if(index == 0) + solvext->setMidx(SolverGeometryExtension::Dependent); + else + solvext->setMidy(SolverGeometryExtension::Dependent); break; } - } } @@ -485,7 +504,7 @@ void Sketch::calculateDependentParametersElements(void) auto element = param2geoelement.find(groups[i][j]); if (element != param2geoelement.end()) { - pDependencyGroups[i].insert(element->second); + pDependencyGroups[i].insert(std::pair(std::get<0>(element->second),std::get<1>(element->second))); } } } @@ -539,6 +558,14 @@ std::set < std::pair< int, Sketcher::PointPos>> Sketch::getDependencyGroup(int g return group; } +std::shared_ptr Sketch::getSolverExtension(int geoId) const +{ + if(geoId >= 0 && geoId < int(solverExtensions.size())) + return solverExtensions[geoId]; + + return nullptr; +} + int Sketch::resetSolver() { clearTemporaryConstraints(); @@ -687,8 +714,8 @@ int Sketch::addPoint(const Part::GeomPoint &point, bool fixed) 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::PointPos::start)); - param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start, 0)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start, 1)); } // return the position of the newly added geometry @@ -746,10 +773,10 @@ int Sketch::addLineSegment(const Part::GeomLineSegment &lineSegment, bool fixed) 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::PointPos::start)); - param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); } // return the position of the newly added geometry @@ -824,15 +851,15 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool 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::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,2)); } // return the position of the newly added geometry @@ -924,17 +951,17 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f GCSsys.addConstraintArcOfEllipseRules(a); if(!fixed) { - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,2)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,3)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,4)); } // return the position of the newly added geometry @@ -1024,17 +1051,17 @@ int Sketch::addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, GCSsys.addConstraintArcOfHyperbolaRules(a); if(!fixed) { - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,2)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,3)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,4)); } @@ -1115,16 +1142,16 @@ int Sketch::addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, boo GCSsys.addConstraintArcOfParabolaRules(a); if(!fixed) { - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,2)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,3)); } // return the position of the newly added geometry @@ -1180,6 +1207,7 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) std::vector spoles; + int i=0; for(std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it){ params.push_back(new double( (*it).x )); params.push_back(new double( (*it).y )); @@ -1191,8 +1219,8 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) spoles.push_back(p); if(!fixed) { - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.x), std::forward_as_tuple(Geoms.size(), Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.y), std::forward_as_tuple(Geoms.size(), Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.x), std::forward_as_tuple(Geoms.size(), Sketcher::PointPos::none,i++)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.y), std::forward_as_tuple(Geoms.size(), Sketcher::PointPos::none,i++)); } } @@ -1204,7 +1232,7 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) 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(), Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size(), Sketcher::PointPos::none,i++)); } } @@ -1286,10 +1314,10 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) 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::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::start,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::end,1)); } // return the position of the newly added geometry @@ -1336,9 +1364,9 @@ int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed) 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::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); } // return the position of the newly added geometry @@ -1400,11 +1428,11 @@ int Sketch::addEllipse(const Part::GeomEllipse &elip, bool fixed) 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::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); - param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::mid,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,0)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,1)); + param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::PointPos::none,2)); } // return the position of the newly added geometry diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 3c9439a943..4ab0ff5d6d 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -36,7 +36,8 @@ namespace Sketcher { - + // Forward declarations + class SolverGeometryExtension; class SketcherExport Sketch :public Base::Persistence { @@ -117,6 +118,8 @@ public: public: std::set < std::pair< int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) const; + std::shared_ptr getSolverExtension(int geoId) const; + public: @@ -441,10 +444,13 @@ protected: std::vector pDependentParametersList; + // map of geoIds to corresponding solverextensions. This is useful when solved geometry is NOT to be assigned to the SketchObject + std::vector> solverExtensions; + 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; + // this map is intended to convert a parameter (double *) into a GeoId/PointPos and parameter number + std::map> param2geoelement; // solving parameters std::vector Parameters; // with memory allocation diff --git a/src/Mod/Sketcher/App/SolverGeometryExtension.cpp b/src/Mod/Sketcher/App/SolverGeometryExtension.cpp index 83305eb7eb..83c90b737b 100644 --- a/src/Mod/Sketcher/App/SolverGeometryExtension.cpp +++ b/src/Mod/Sketcher/App/SolverGeometryExtension.cpp @@ -24,6 +24,8 @@ #include +#include + #include "SolverGeometryExtension.h" using namespace Sketcher; @@ -33,7 +35,6 @@ using namespace Sketcher; TYPESYSTEM_SOURCE(Sketcher::SolverGeometryExtension,Part::GeometryExtension) SolverGeometryExtension::SolverGeometryExtension(): - Edge(SolverGeometryExtension::Dependent), Start(SolverGeometryExtension::Dependent), Mid(SolverGeometryExtension::Dependent), End(SolverGeometryExtension::Dependent) @@ -68,3 +69,101 @@ PyObject * SolverGeometryExtension::getPyObject(void) THROWM(Base::NotImplementedError, "SolverGeometryExtension does not have a Python counterpart"); } +SolverGeometryExtension::PointParameterStatus SolverGeometryExtension::getPoint(Sketcher::PointPos pos) const { + if(pos==Sketcher::PointPos::start) + return getStartPoint(); + if(pos==Sketcher::PointPos::end) + return getEndPoint(); + if(pos==Sketcher::PointPos::mid) + return getMidPoint(); + + THROWM(Base::ValueError, "SolverGeometryExtension - getPoint: Edge is not a point"); +} + +void SolverGeometryExtension::notifyAttachment(Part::Geometry * geo) +{ + // maps type to number of solver parameters taken by the edge + static std::map edgeParamMap = { + {Part::GeomPoint::getClassTypeId(), 0}, + {Part::GeomLineSegment::getClassTypeId(), 0}, + {Part::GeomArcOfCircle::getClassTypeId(), 3}, + {Part::GeomCircle::getClassTypeId(), 1}, + {Part::GeomArcOfEllipse::getClassTypeId(), 5}, + {Part::GeomEllipse::getClassTypeId(), 3}, + {Part::GeomArcOfHyperbola::getClassTypeId(), 5}, + {Part::GeomArcOfParabola::getClassTypeId(), 4}, + {Part::GeomBSplineCurve::getClassTypeId(), 0} // is dynamic + }; + + GeometryType = geo->getTypeId(); + + auto result = edgeParamMap.find(GeometryType); + + if( result == edgeParamMap.end() ) + THROWM(Base::TypeError, "SolverGeometryExtension - notifyAttachment - Geometry not supported!!"); + + auto nedgeparams = (*result).second; + + if(nedgeparams>0) + Edge.init(nedgeparams); +} + +void SolverGeometryExtension::ensureType(const Base::Type & type) +{ + if(GeometryType != type) + THROWM(Base::TypeError, "SolverGeometryExtension - requested edge parameters do not match underlying type!"); +} + +SolverGeometryExtension::Point & SolverGeometryExtension::getPoint() +{ + ensureType(Part::GeomPoint::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::Line & SolverGeometryExtension::getLine() +{ + ensureType(Part::GeomLineSegment::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::Arc & SolverGeometryExtension::getArc() +{ + ensureType(Part::GeomArcOfCircle::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::Circle & SolverGeometryExtension::getCircle() +{ + ensureType(Part::GeomCircle::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::ArcOfEllipse & SolverGeometryExtension::getArcOfEllipse() +{ + ensureType(Part::GeomArcOfEllipse::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::Ellipse & SolverGeometryExtension::getEllipse() +{ + ensureType(Part::GeomEllipse::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::ArcOfHyperbola & SolverGeometryExtension::getArcOfHyperbola() +{ + ensureType(Part::GeomArcOfHyperbola::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::ArcOfParabola & SolverGeometryExtension::getArcOfParabola() +{ + ensureType(Part::GeomArcOfParabola::getClassTypeId()); + return static_cast(Edge); +} + +SolverGeometryExtension::BSpline & SolverGeometryExtension::getBSpline() +{ + ensureType(Part::GeomBSplineCurve::getClassTypeId()); + return static_cast(Edge); +} diff --git a/src/Mod/Sketcher/App/SolverGeometryExtension.h b/src/Mod/Sketcher/App/SolverGeometryExtension.h index aee0130132..38301255e5 100644 --- a/src/Mod/Sketcher/App/SolverGeometryExtension.h +++ b/src/Mod/Sketcher/App/SolverGeometryExtension.h @@ -26,6 +26,10 @@ #include #include +#include "GeoEnum.h" + +#include + namespace Sketcher { @@ -45,36 +49,244 @@ public: NumParameterStatus }; + class PointParameterStatus { + public: + PointParameterStatus(ParameterStatus status) {setStatus(status);} + PointParameterStatus(ParameterStatus statusx, ParameterStatus statusy) {setStatus(statusx, statusy);} + + PointParameterStatus(const PointParameterStatus &) = default; + PointParameterStatus & operator=(const PointParameterStatus &) = default; + PointParameterStatus(PointParameterStatus &&) = default; + PointParameterStatus & operator=(PointParameterStatus &&) = default; + + ParameterStatus getStatus() const { return (xstatus == Independent && ystatus == Independent)?Independent:Dependent;} + ParameterStatus getStatusx() const { return xstatus;} + ParameterStatus getStatusy() const { return ystatus;} + + bool isXDoF() {return xstatus == Dependent;} + bool isYDoF() {return ystatus == Dependent;} + + int getDoFs() { + bool xfree = isXDoF(); + bool yfree = isYDoF(); + + if(xfree && yfree) + return 2; + else if(xfree || yfree) + return 1; + else + return 0; + } + + void setStatus(ParameterStatus status) {xstatus=status; ystatus=status;} + void setStatus(ParameterStatus statusx, ParameterStatus statusy) {xstatus=statusx; ystatus=statusy;} + void setStatusx(ParameterStatus statusx) {xstatus=statusx;} + void setStatusy(ParameterStatus statusy) {ystatus=statusy;} + + private: + ParameterStatus xstatus; + ParameterStatus ystatus; + }; + + class EdgeParameterStatus + { + public: + EdgeParameterStatus() = default; + + void init(int nparams) { pstatus.resize(nparams, ParameterStatus::Dependent);} + + ParameterStatus getStatus() const { + return std::all_of(pstatus.begin(), pstatus.end(), [](const auto & v){ return v == Independent;})?Independent:Dependent; + } + + void setStatus(ParameterStatus status) { std::fill(pstatus.begin(), pstatus.end(), status);} + + void setStatus(int index, ParameterStatus status) { + if(index > int(pstatus.size())) + pstatus.resize(index+1,ParameterStatus::Dependent); + + pstatus.at(index) = status; + + }; + + protected: + std::vector pstatus; + + }; + + class Point : public EdgeParameterStatus + { + public: + Point() = default; + }; + + class Line : public EdgeParameterStatus + { + public: + Line() = default; + }; + + class Arc : public EdgeParameterStatus + { + public: + Arc() = default; + + ParameterStatus getRadiusStatus() const {return pstatus[0];} + ParameterStatus getStartParameter() const {return pstatus[1];} + ParameterStatus getEndParameter() const {return pstatus[2];} + }; + + class Circle : public EdgeParameterStatus + { + public: + Circle() = default; + + ParameterStatus getRadiusStatus() const {return pstatus[0];} + bool isRadiusDoF() const {return pstatus[0] == Dependent;} + }; + + class ArcOfEllipse : public EdgeParameterStatus + { + public: + ArcOfEllipse() = default; + + ParameterStatus getFocusXStatus() const {return pstatus[0];} + ParameterStatus getFocusYStatus() const {return pstatus[1];} + ParameterStatus getFocusMinorRadiusStatus() const {return pstatus[2];} + ParameterStatus getStartParameter() const {return pstatus[3];} + ParameterStatus getEndParameter() const {return pstatus[4];} + + bool isFocusDoF() const {return pstatus[0] == Dependent || pstatus[1] == Dependent;} + bool isMinorRadiusDoF() const {return (pstatus[2] == Dependent);} + }; + + class Ellipse : public EdgeParameterStatus + { + public: + Ellipse() = default; + + ParameterStatus getFocusXStatus() const {return pstatus[0];} + ParameterStatus getFocusYStatus() const {return pstatus[1];} + ParameterStatus getFocusMinorRadiusStatus() const {return pstatus[2];} + + bool isFocusDoF() const {return pstatus[0] == Dependent || pstatus[1] == Dependent;} + bool isMinorRadiusDoF() const {return (pstatus[2] == Dependent);} + }; + + class ArcOfHyperbola : public EdgeParameterStatus + { + public: + ArcOfHyperbola() = default; + + ParameterStatus getFocusXStatus() const {return pstatus[0];} + ParameterStatus getFocusYStatus() const {return pstatus[1];} + ParameterStatus getFocusMinorRadiusStatus() const {return pstatus[2];} + ParameterStatus getStartParameter() const {return pstatus[3];} + ParameterStatus getEndParameter() const {return pstatus[4];} + }; + + class ArcOfParabola : public EdgeParameterStatus + { + public: + ArcOfParabola() = default; + + ParameterStatus getFocusXStatus() const {return pstatus[0];} + ParameterStatus getFocusYStatus() const {return pstatus[1];} + }; + + class BSpline : public EdgeParameterStatus + { + public: + BSpline() = default; + + ParameterStatus getPoleXStatus(int poleindex) const + { + int npoles = pstatus.size() / 3; + + if(poleindex < npoles) + return pstatus[poleindex*2]; + + THROWM(Base::IndexError, "Pole index out of range") + + } + + ParameterStatus getPoleYStatus(int poleindex) const + { + int npoles = pstatus.size() / 3; + + if(poleindex < npoles) + return pstatus[poleindex*2+1]; + + THROWM(Base::IndexError, "Pole index out of range") + + } + + ParameterStatus getWeightStatus(int weightindex) const + { + int nweights = pstatus.size() / 3; + + if(weightindex < nweights) + return pstatus[nweights*2 + weightindex]; + + THROWM(Base::IndexError, "Weight index out of range") + } + }; + + SolverGeometryExtension(); - SolverGeometryExtension(long cid); virtual ~SolverGeometryExtension() override = default; virtual std::unique_ptr copy(void) const override; virtual PyObject *getPyObject(void) override; - SolverStatus getGeometry() const {return ( Edge == Independent && - Start == Independent && - End == Independent && - Mid == Independent) ? FullyConstraint : NotFullyConstraint;} + virtual void notifyAttachment(Part::Geometry * geo) override; - ParameterStatus getEdge() const {return Edge;} - void setEdge(ParameterStatus status) {Edge = status;} + SolverStatus getGeometry() const {return ( Edge.getStatus() == Independent && + Start.getStatus() == Independent && + End.getStatus() == Independent && + Mid.getStatus() == Independent) ? FullyConstraint : NotFullyConstraint;} - ParameterStatus getStart() const {return Start;} - void setStart(ParameterStatus status) {Start = status;} + ParameterStatus getEdge() const {return Edge.getStatus();} + Point & getPoint(); + Line & getLine(); + Arc & getArc(); + Circle & getCircle(); + ArcOfEllipse & getArcOfEllipse(); + Ellipse & getEllipse(); + ArcOfHyperbola & getArcOfHyperbola(); + ArcOfParabola & getArcOfParabola(); + BSpline & getBSpline(); + EdgeParameterStatus getEdgeParameters() {return Edge;} + void setEdge(ParameterStatus status) {Edge.setStatus(status);} + void setEdge(int paramindex, ParameterStatus status) {Edge.setStatus(paramindex,status);} - ParameterStatus getMid() const {return Mid;} - void setMid(ParameterStatus status) {Mid = status;} + ParameterStatus getStart() const {return Start.getStatus();} + PointParameterStatus getStartPoint() const {return Start;} + void setStart(ParameterStatus xstatus, ParameterStatus ystatus) {Start.setStatus(xstatus,ystatus);} + void setStartx(ParameterStatus xstatus) {Start.setStatusx(xstatus);} + void setStarty(ParameterStatus ystatus) {Start.setStatusy(ystatus);} - ParameterStatus getEnd() const {return End;} - void setEnd(ParameterStatus status) {End = status;} + ParameterStatus getMid() const {return Mid.getStatus();} + PointParameterStatus getMidPoint() const {return Mid;} + void setMid(ParameterStatus xstatus, ParameterStatus ystatus) {Mid.setStatus(xstatus,ystatus);} + void setMidx(ParameterStatus xstatus) {Mid.setStatusx(xstatus);} + void setMidy(ParameterStatus ystatus) {Mid.setStatusy(ystatus);} + + ParameterStatus getEnd() const {return End.getStatus();} + PointParameterStatus getEndPoint() const {return End;} + + void setEnd(ParameterStatus xstatus, ParameterStatus ystatus) {End.setStatus(xstatus,ystatus);} + void setEndx(ParameterStatus xstatus) {End.setStatusx(xstatus);} + void setEndy(ParameterStatus ystatus) {End.setStatusy(ystatus);} + + PointParameterStatus getPoint(Sketcher::PointPos pos) const; void init(ParameterStatus status) { - Edge = status; - Start = status; - Mid = status; - End = status; + Edge.setStatus(status); + Start.setStatus(status); + Mid.setStatus(status); + End.setStatus(status); } protected: @@ -83,11 +295,16 @@ protected: private: SolverGeometryExtension(const SolverGeometryExtension&) = default; + void ensureType(const Base::Type & type); + private: - ParameterStatus Edge; - ParameterStatus Start; - ParameterStatus Mid; - ParameterStatus End; + EdgeParameterStatus Edge; + + PointParameterStatus Start; + PointParameterStatus Mid; + PointParameterStatus End; + + Base::Type GeometryType; }; } //namespace Sketcher