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.
This commit is contained in:
Abdullah Tahiri
2020-12-15 06:40:50 +01:00
committed by abdullahtahiriyo
parent 5a20215e65
commit 0888c0dd64
2 changed files with 214 additions and 92 deletions

View File

@@ -55,10 +55,13 @@
#include <Mod/Part/App/LineSegmentPy.h>
#include <Mod/Part/App/BSplineCurvePy.h>
#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<GeoDef>::iterator it = Geoms.begin(); it != Geoms.end(); ++it)
if (it->geo) delete it->geo;
@@ -159,7 +165,7 @@ int Sketch::setUpSketch(const std::vector<Part::Geometry *> &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<double *> 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<Sketcher::SolverGeometryExtension>());
auto solvext = std::static_pointer_cast<Sketcher::SolverGeometryExtension>(
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<Sketcher::SolverGeometryExtension>(
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 &parabolaSegment, 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<double *> sweights;
for(std::vector<double>::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<double *> 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;
}

View File

@@ -108,6 +108,11 @@ public:
inline const std::vector<int> &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<int> Conflicting;
std::vector<int> Redundant;
std::vector<double *> pconstraintplistOut;
std::vector<double *> 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<double *, std::pair<int,Sketcher::PointPos>> param2geoelement;
// solving parameters
std::vector<double*> Parameters; // with memory allocation