Merge branch 'logari81/sketch-diagnostics'

This commit is contained in:
logari81 2012-05-27 12:11:19 +02:00
commit dbce31d44f
10 changed files with 472 additions and 334 deletions

View File

@ -96,8 +96,9 @@ void Sketch::clear(void)
Conflicting.clear();
}
int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList, const std::vector<Constraint *> &ConstraintList,
bool withDiagnose, int extGeoCount)
int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList,
const std::vector<Constraint *> &ConstraintList,
int extGeoCount)
{
clear();
@ -119,13 +120,11 @@ int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList, const std:
addConstraints(ConstraintList);
GCSsys.clearByTag(-1);
GCSsys.clearByTag(-2);
GCSsys.initSolution(Parameters);
if (withDiagnose)
return diagnose();
else
return 0;
GCSsys.declareUnknowns(Parameters);
GCSsys.initSolution();
GCSsys.getConflicting(Conflicting);
GCSsys.getRedundant(Redundant);
return GCSsys.dofsNumber();
}
const char* nameByType(Sketch::GeoType type)
@ -744,10 +743,7 @@ int Sketch::addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2,
GCS::Point &p1 = Points[pointId1];
GCS::Point &p2 = Points[pointId2];
int tag = ++ConstraintsCounter;
// trick: we do not tag coincidence constraints in order to exclude
// them from the diagnosing of conflicts
//GCSsys.addConstraintP2PCoincident(p1, p2, tag);
GCSsys.addConstraintP2PCoincident(p1, p2);
GCSsys.addConstraintP2PCoincident(p1, p2, tag);
return ConstraintsCounter;
}
return -1;
@ -1569,7 +1565,6 @@ int Sketch::solve(void)
Base::TimeInfo start_time;
if (!isInitMove) { // make sure we are in single subsystem mode
GCSsys.clearByTag(-1);
GCSsys.clearByTag(-2);
isFine = true;
}
@ -1593,32 +1588,33 @@ int Sketch::solve(void)
break;
case 3: // last resort: augment the system with a second subsystem and use the SQP solver
solvername = "SQP(augmented system)";
GCSsys.clearByTag(-1);
GCSsys.clearByTag(-2);
InitParameters.resize(Parameters.size());
int i=0;
for (std::vector<double*>::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) {
InitParameters[i] = **it;
GCSsys.addConstraintEqual(*it, &InitParameters[i], -2);
GCSsys.addConstraintEqual(*it, &InitParameters[i], -1);
}
GCSsys.initSolution(Parameters);
GCSsys.initSolution();
ret = GCSsys.solve(isFine);
break;
}
// if successfully solved try write the parameters back
// if successfully solved try to write the parameters back
if (ret == GCS::Success) {
GCSsys.applySolution();
valid_solution = updateGeometry();
if (!valid_solution)
if (!valid_solution) {
GCSsys.undoSolution();
updateGeometry();
Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str());
}
} else {
valid_solution = false;
//Base::Console().Log("NotSolved ");
}
if (soltype == 3) // cleanup temporary constraints of the augmented system
GCSsys.clearByTag(-2);
GCSsys.clearByTag(-1);
if (valid_solution) {
if (soltype == 1)
@ -1637,11 +1633,6 @@ int Sketch::solve(void)
}
} // soltype
if (!valid_solution) { // undo any changes
GCSsys.undoSolution();
updateGeometry();
}
Base::TimeInfo end_time;
//Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str());
SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time);
@ -1655,7 +1646,6 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine)
geoId = checkGeoId(geoId);
GCSsys.clearByTag(-1);
GCSsys.clearByTag(-2);
// don't try to move sketches that contain conflicting constraints
if (hasConflicts()) {
@ -1760,7 +1750,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine)
}
InitParameters = MoveParameters;
GCSsys.initSolution(Parameters);
GCSsys.initSolution();
isInitMove = true;
return 0;
}
@ -1838,18 +1828,6 @@ Base::Vector3d Sketch::getPoint(int geoId, PointPos pos)
return Base::Vector3d();
}
int Sketch::diagnose(void)
{
Conflicting.clear();
if (GCSsys.isInit()) {
int dofs = GCSsys.diagnose(Parameters, Conflicting);
return dofs;
}
else {
return -1;
}
}
TopoShape Sketch::toShape(void) const

View File

@ -53,9 +53,21 @@ public:
int solve(void);
/// delete all geometry and constraints, leave an empty sketch
void clear(void);
/// set the sketch up with geoms and constraints
/** set the sketch up with geoms and constraints
*
* returns the degree of freedom of a sketch and calculates a list of
* conflicting constraints
*
* 0 degrees of freedom correspond to a fully constrained sketch
* -1 degrees of freedom correspond to an over-constrained sketch
* positive degrees of freedom correspond to an under-constrained sketch
*
* an over-constrained sketch will always contain conflicting constraints
* a fully constrained or under-constrained sketch may contain conflicting
* constraints or may not
*/
int setUpSketch(const std::vector<Part::Geometry *> &GeoList, const std::vector<Constraint *> &ConstraintList,
bool withDiagnose=true, int extGeoCount=0);
int extGeoCount=0);
/// return the actual geometry of the sketch a TopoShape
Part::TopoShape toShape(void) const;
/// add unspecified geometry
@ -71,20 +83,10 @@ public:
/// retrieves a point
Base::Vector3d getPoint(int geoId, PointPos pos);
/** returns the degree of freedom of a sketch and calculates a list of
* conflicting constraints
*
* 0 degrees of freedom correspond to a fully constrained sketch
* -1 degrees of freedom correspond to an over-constrained sketch
* positive degrees of freedom correspond to an under-constrained sketch
*
* an over-constrained sketch will always contain conflicting constraints
* a fully constrained or under-constrained sketch may contain conflicting
* constraints or may not
*/
int diagnose(void);
bool hasConflicts(void) const { return (Conflicting.size() > 0); };
const std::vector<int> &getConflicting(void) const { return Conflicting; };
bool hasConflicts(void) const { return (Conflicting.size() > 0); }
const std::vector<int> &getConflicting(void) const { return Conflicting; }
bool hasRedundancies(void) const { return (Redundant.size() > 0); }
const std::vector<int> &getRedundant(void) const { return Redundant; }
/** set the datum of a distance or angle constraint to a certain value and solve
* This can cause the solving to fail!
@ -201,6 +203,7 @@ protected:
GCS::System GCSsys;
int ConstraintsCounter;
std::vector<int> Conflicting;
std::vector<int> Redundant;
// solving parameters
std::vector<double*> Parameters; // with memory allocation

View File

@ -97,7 +97,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void)
rebuildExternalGeometry();
Sketch sketch;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
true, getExternalGeometryCount());
getExternalGeometryCount());
if (dofs < 0) { // over-constrained sketch
std::string msg="Over-constrained sketch\n";
appendConflictMsg(sketch.getConflicting(), msg);
@ -108,6 +108,11 @@ App::DocumentObjectExecReturn *SketchObject::execute(void)
appendConflictMsg(sketch.getConflicting(), msg);
return new App::DocumentObjectExecReturn(msg.c_str(),this);
}
if (sketch.hasRedundancies()) { // redundant constraints
std::string msg="Sketch with redundant constraints\n";
appendRedundantMsg(sketch.getRedundant(), msg);
return new App::DocumentObjectExecReturn(msg.c_str(),this);
}
// solve the sketch
if (sketch.solve() != 0)
@ -128,7 +133,7 @@ int SketchObject::hasConflicts(void) const
// set up a sketch (including dofs counting and diagnosing of conflicts)
Sketch sketch;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
true, getExternalGeometryCount());
getExternalGeometryCount());
if (dofs < 0) // over-constrained sketch
return -2;
if (sketch.hasConflicts()) // conflicting constraints
@ -166,7 +171,7 @@ int SketchObject::setDatum(int ConstrId, double Datum)
// set up a sketch (including dofs counting and diagnosing of conflicts)
Sketch sketch;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
true, getExternalGeometryCount());
getExternalGeometryCount());
int err=0;
if (dofs < 0) // over-constrained sketch
err = -3;
@ -192,7 +197,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP
{
Sketch sketch;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
true, getExternalGeometryCount());
getExternalGeometryCount());
if (dofs < 0) // over-constrained sketch
return -1;
if (sketch.hasConflicts()) // conflicting constraints
@ -1388,10 +1393,32 @@ void SketchObject::appendConflictMsg(const std::vector<int> &conflicting, std::s
if (msg.length() > 0)
ss << msg;
if (conflicting.size() > 0) {
ss << "Please remove at least one of the constraints (" << conflicting[0];
if (conflicting.size() == 1)
ss << "Please remove the following constraint:\n";
else
ss << "Please remove at least one of the following constraints:\n";
ss << conflicting[0];
for (unsigned int i=1; i < conflicting.size(); i++)
ss << ", " << conflicting[i];
ss << ")\n";
ss << "\n";
}
msg = ss.str();
}
void SketchObject::appendRedundantMsg(const std::vector<int> &redundant, std::string &msg)
{
std::stringstream ss;
if (msg.length() > 0)
ss << msg;
if (redundant.size() > 0) {
if (redundant.size() == 1)
ss << "Please remove the following redundant constraint:\n";
else
ss << "Please remove the following redundant constraints:\n";
ss << redundant[0];
for (unsigned int i=1; i < redundant.size(); i++)
ss << ", " << redundant[i];
ss << "\n";
}
msg = ss.str();
}

View File

@ -136,6 +136,8 @@ public:
/// generates a warning message about constraint conflicts and appends it to the given message
static void appendConflictMsg(const std::vector<int> &conflicting, std::string &msg);
/// generates a warning message about redundant constraints and appends it to the given message
static void appendRedundantMsg(const std::vector<int> &redundant, std::string &msg);
// from base class
virtual PyObject *getPyObject(void);

View File

@ -41,19 +41,20 @@ typedef boost::adjacency_list <boost::vecS, boost::vecS, boost::undirectedS> Gra
// System
System::System()
: clist(0),
: plist(0), clist(0),
c2p(), p2c(),
subsyslist(0),
reference(),
init(false)
subSystems(0), subSystemsAux(0),
reference(0),
hasUnknowns(false), hasDiagnosis(false), isInit(false)
{
}
System::System(std::vector<Constraint *> clist_)
: c2p(), p2c(),
subsyslist(0),
reference(),
init(false)
: plist(0),
c2p(), p2c(),
subSystems(0), subSystemsAux(0),
reference(0),
hasUnknowns(false), hasDiagnosis(false), isInit(false)
{
// create own (shallow) copy of constraints
for (std::vector<Constraint *>::iterator constr=clist_.begin();
@ -125,7 +126,16 @@ System::~System()
void System::clear()
{
clearReference();
plist.clear();
pIndex.clear();
hasUnknowns = false;
hasDiagnosis = false;
redundant.clear();
conflictingTags.clear();
redundantTags.clear();
reference.clear();
clearSubSystems();
free(clist);
c2p.clear();
@ -148,7 +158,9 @@ void System::clearByTag(int tagId)
int System::addConstraint(Constraint *constr)
{
clearReference();
isInit = false;
if (constr->getTag() >= 0) // negatively tagged constraints have no impact
hasDiagnosis = false; // on the diagnosis
clist.push_back(constr);
VEC_pD constr_params = constr->params();
@ -163,12 +175,15 @@ int System::addConstraint(Constraint *constr)
void System::removeConstraint(Constraint *constr)
{
clearReference();
clearSubSystems();
std::vector<Constraint *>::iterator it;
it = std::find(clist.begin(), clist.end(), constr);
if (it == clist.end())
return;
clist.erase(it);
if (constr->getTag() >= 0)
hasDiagnosis = false;
clearSubSystems();
VEC_pD constr_params = c2p[constr];
for (VEC_pD::const_iterator param=constr_params.begin();
@ -545,9 +560,18 @@ void System::rescaleConstraint(int id, double coeff)
clist[id]->rescale(coeff);
}
void System::initSolution(VEC_pD &params)
void System::declareUnknowns(VEC_pD &params)
{
plist = params;
pIndex.clear();
for (int i=0; i < int(plist.size()); ++i)
pIndex[plist[i]] = i;
hasUnknowns = true;
}
void System::initSolution()
{
// - Stores the current parameters values in the vector "reference"
// - identifies any decoupled subsystems and partitions the original
// system into corresponding components
// - Stores the current parameters in the vector "reference"
@ -556,18 +580,38 @@ void System::initSolution(VEC_pD &params)
// - Organizes the rest of constraints into two subsystems for
// tag ids >=0 and < 0 respectively and applies the
// system reduction specified in the previous step
MAP_pD_I pIndex;
for (int i=0; i < int(params.size()); ++i)
pIndex[params[i]] = i;
isInit = false;
if (!hasUnknowns)
return;
// storing reference configuration
setReference();
// diagnose conflicting or redundant constraints
if (!hasDiagnosis) {
diagnose();
if (!hasDiagnosis)
return;
}
std::vector<Constraint *> clistR;
if (redundant.size()) {
for (std::vector<Constraint *>::const_iterator constr=clist.begin();
constr != clist.end(); ++constr)
if (redundant.count(*constr) == 0)
clistR.push_back(*constr);
}
else
clistR = clist;
// partitioning into decoupled components
Graph g;
for (int i=0; i < int(params.size() + clist.size()); i++)
for (int i=0; i < int(plist.size() + clistR.size()); i++)
boost::add_vertex(g);
int cvtid = int(params.size());
for (std::vector<Constraint *>::const_iterator constr=clist.begin();
constr != clist.end(); ++constr, cvtid++) {
int cvtid = int(plist.size());
for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
constr != clistR.end(); ++constr, cvtid++) {
VEC_pD &cparams = c2p[*constr];
for (VEC_pD::const_iterator param=cparams.begin();
param != cparams.end(); ++param) {
@ -580,113 +624,131 @@ void System::initSolution(VEC_pD &params)
VEC_I components(boost::num_vertices(g));
int componentsSize = boost::connected_components(g, &components[0]);
clearReference();
for (VEC_pD::const_iterator param=params.begin();
param != params.end(); ++param)
reference[*param] = **param;
// identification of equality constraints and parameter reduction
std::set<Constraint *> eliminated; // constraints that will be eliminated through reduction
reductionmap.clear();
std::set<Constraint *> reducedConstrs; // constraints that will be eliminated through reduction
reductionmaps.clear(); // destroy any maps
reductionmaps.resize(componentsSize); // create empty maps to be filled in
{
VEC_pD reduced_params=params;
VEC_pD reducedParams=plist;
for (std::vector<Constraint *>::const_iterator constr=clist.begin();
constr != clist.end(); ++constr) {
for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
constr != clistR.end(); ++constr) {
if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) {
MAP_pD_I::const_iterator it1,it2;
it1 = pIndex.find((*constr)->params()[0]);
it2 = pIndex.find((*constr)->params()[1]);
if (it1 != pIndex.end() && it2 != pIndex.end()) {
eliminated.insert(*constr);
double *p_kept = reduced_params[it1->second];
double *p_replaced = reduced_params[it2->second];
for (int i=0; i < int(params.size()); ++i)
if (reduced_params[i] == p_replaced)
reduced_params[i] = p_kept;
reducedConstrs.insert(*constr);
double *p_kept = reducedParams[it1->second];
double *p_replaced = reducedParams[it2->second];
for (int i=0; i < int(plist.size()); ++i)
if (reducedParams[i] == p_replaced)
reducedParams[i] = p_kept;
}
}
}
for (int i=0; i < int(params.size()); ++i)
if (params[i] != reduced_params[i])
reductionmap[params[i]] = reduced_params[i];
for (int i=0; i < int(plist.size()); ++i)
if (plist[i] != reducedParams[i]) {
int cid = components[i];
reductionmaps[cid][plist[i]] = reducedParams[i];
}
}
std::vector< std::vector<Constraint *> > clists0(componentsSize),
clists1(componentsSize),
clists2(componentsSize);
int i = int(params.size());
for (std::vector<Constraint *>::const_iterator constr=clist.begin();
constr != clist.end(); ++constr, i++) {
if (eliminated.count(*constr) == 0) {
int id = components[i];
if ((*constr)->getTag() >= 0)
clists0[id].push_back(*constr);
else if ((*constr)->getTag() == -1) // move constraints
clists1[id].push_back(*constr);
else // distance from reference constraints
clists2[id].push_back(*constr);
clists.clear(); // destroy any lists
clists.resize(componentsSize); // create empty lists to be filled in
int i = int(plist.size());
for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
constr != clistR.end(); ++constr, i++) {
if (reducedConstrs.count(*constr) == 0) {
int cid = components[i];
clists[cid].push_back(*constr);
}
}
std::vector< std::vector<double *> > plists(componentsSize);
for (int i=0; i < int(params.size()); ++i) {
int id = components[i];
plists[id].push_back(params[i]);
plists.clear(); // destroy any lists
plists.resize(componentsSize); // create empty lists to be filled in
for (int i=0; i < int(plist.size()); ++i) {
int cid = components[i];
plists[cid].push_back(plist[i]);
}
// calculates subSystems and subSystemsAux from clists, plists and reductionmaps
clearSubSystems();
for (int cid=0; cid < componentsSize; cid++) {
subsyslist.push_back(std::vector<SubSystem *>(0));
if (clists0[cid].size() > 0)
subsyslist[cid].push_back(new SubSystem(clists0[cid], plists[cid], reductionmap));
if (clists1[cid].size() > 0)
subsyslist[cid].push_back(new SubSystem(clists1[cid], plists[cid], reductionmap));
if (clists2[cid].size() > 0)
subsyslist[cid].push_back(new SubSystem(clists2[cid], plists[cid], reductionmap));
for (int cid=0; cid < clists.size(); cid++) {
std::vector<Constraint *> clist0, clist1;
for (std::vector<Constraint *>::const_iterator constr=clists[cid].begin();
constr != clists[cid].end(); ++constr) {
if ((*constr)->getTag() >= 0)
clist0.push_back(*constr);
else // move or distance from reference constraints
clist1.push_back(*constr);
}
subSystems.push_back(NULL);
subSystemsAux.push_back(NULL);
if (clist0.size() > 0)
subSystems[cid] = new SubSystem(clist0, plists[cid], reductionmaps[cid]);
if (clist1.size() > 0)
subSystemsAux[cid] = new SubSystem(clist1, plists[cid], reductionmaps[cid]);
}
init = true;
isInit = true;
}
void System::clearReference()
void System::setReference()
{
init = false;
reference.clear();
reference.reserve(plist.size());
for (VEC_pD::const_iterator param=plist.begin();
param != plist.end(); ++param)
reference.push_back(**param);
}
void System::resetToReference()
{
for (MAP_pD_D::const_iterator it=reference.begin();
it != reference.end(); ++it)
*(it->first) = it->second;
if (reference.size() == plist.size()) {
VEC_D::const_iterator ref=reference.begin();
VEC_pD::iterator param=plist.begin();
for (; ref != reference.end(); ++ref, ++param)
**param = *ref;
}
}
int System::solve(VEC_pD &params, bool isFine, Algorithm alg)
{
initSolution(params);
declareUnknowns(params);
initSolution();
return solve(isFine, alg);
}
int System::solve(bool isFine, Algorithm alg)
{
if (!isInit)
return Failed;
bool isReset = false;
// return success by default in order to permit coincidence constraints to be applied
// even if no other system has to be solved
int res = Success;
for (int cid=0; cid < int(subsyslist.size()); cid++) {
if (subsyslist[cid].size() > 0 && !isReset) {
for (int cid=0; cid < int(subSystems.size()); cid++) {
if ((subSystems[cid] || subSystemsAux[cid]) && !isReset) {
resetToReference();
isReset = true;
}
if (subsyslist[cid].size() == 1)
res = std::max(res, solve(subsyslist[cid][0], isFine, alg));
else if (subsyslist[cid].size() == 2)
res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][1], isFine));
else if (subsyslist[cid].size() > 2)
// subsystem 1 has higher priority than subsystems 2,3,...
// these subsystems act like a preconditioner
for (int i=subsyslist[cid].size()-1; i > 0; i--)
res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][i], isFine));
if (subSystems[cid] && subSystemsAux[cid])
res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine));
else if (subSystems[cid])
res = std::max(res, solve(subSystems[cid], isFine, alg));
else if (subSystemsAux[cid])
res = std::max(res, solve(subSystemsAux[cid], isFine, alg));
}
if (res == Success) {
for (std::set<Constraint *>::const_iterator constr=redundant.begin();
constr != redundant.end(); constr++)
if ((*constr)->error() > XconvergenceFine) {
res = Converged;
return res;
}
}
return res;
}
@ -1068,7 +1130,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
int xsizeB = subsysB->pSize();
int csizeA = subsysA->cSize();
VEC_pD plist(xsizeA+xsizeB);
VEC_pD plistAB(xsizeA+xsizeB);
{
VEC_pD plistA, plistB;
subsysA->getParamList(plistA);
@ -1079,10 +1141,10 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
VEC_pD::const_iterator it;
it = std::set_union(plistA.begin(),plistA.end(),
plistB.begin(),plistB.end(),plist.begin());
plist.resize(it-plist.begin());
plistB.begin(),plistB.end(),plistAB.begin());
plistAB.resize(it-plistAB.begin());
}
int xsize = plist.size();
int xsize = plistAB.size();
Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize);
Eigen::MatrixXd JA(csizeA, xsize);
@ -1100,12 +1162,12 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
subsysA->redirectParams();
subsysB->redirectParams();
subsysB->getParams(plist,x);
subsysA->getParams(plist,x);
subsysB->setParams(plist,x); // just to ensure that A and B are synchronized
subsysB->getParams(plistAB,x);
subsysA->getParams(plistAB,x);
subsysB->setParams(plistAB,x); // just to ensure that A and B are synchronized
subsysB->calcGrad(plist,grad);
subsysA->calcJacobi(plist,JA);
subsysB->calcGrad(plistAB,grad);
subsysA->calcJacobi(plistAB,JA);
subsysA->calcResidual(resA);
double convergence = isFine ? XconvergenceFine : XconvergenceRough;
@ -1130,7 +1192,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
double tau=0.5;
double rho=0.5;
double alpha=1;
alpha = std::min(alpha, subsysA->maxStep(plist,xdir));
alpha = std::min(alpha, subsysA->maxStep(plistAB,xdir));
// Eq. 18.32
// double mu = lambda.lpNorm<Eigen::Infinity>() + 0.01;
@ -1148,8 +1210,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>();
x = x0 + alpha * xdir;
subsysA->setParams(plist,x);
subsysB->setParams(plist,x);
subsysA->setParams(plistAB,x);
subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA);
double f = subsysB->error() + mu * resA.lpNorm<1>();
@ -1161,8 +1223,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
// Eigen::ComputeThinV).solve(-resA);
xdir1 = -Y*resA;
x += xdir1; // = x0 + alpha * xdir + xdir1
subsysA->setParams(plist,x);
subsysB->setParams(plist,x);
subsysA->setParams(plistAB,x);
subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA);
f = subsysB->error() + mu * resA.lpNorm<1>();
if (f < f0 + eta * alpha * deriv)
@ -1172,8 +1234,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
if (alpha < 1e-8) // let the linesearch fail
alpha = 0.;
x = x0 + alpha * xdir;
subsysA->setParams(plist,x);
subsysB->setParams(plist,x);
subsysA->setParams(plistAB,x);
subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA);
f = subsysB->error() + mu * resA.lpNorm<1>();
if (alpha < 1e-8) // let the linesearch fail
@ -1186,8 +1248,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
y = grad - JA.transpose() * lambda;
{
subsysB->calcGrad(plist,grad);
subsysA->calcJacobi(plist,JA);
subsysB->calcGrad(plistAB,grad);
subsysA->calcJacobi(plistAB,JA);
subsysA->calcResidual(resA);
}
y = grad - JA.transpose() * lambda - y; // Eq. 18.13
@ -1225,13 +1287,15 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
void System::applySolution()
{
for (int cid=0; cid < int(subsyslist.size()); cid++)
for (int i=subsyslist[cid].size()-1; i >= 0; i--)
subsyslist[cid][i]->applySolution();
for (MAP_pD_pD::const_iterator it=reductionmap.begin();
it != reductionmap.end(); ++it)
*(it->first) = *(it->second);
for (int cid=0; cid < int(subSystems.size()); cid++) {
if (subSystemsAux[cid])
subSystemsAux[cid]->applySolution();
if (subSystems[cid])
subSystems[cid]->applySolution();
for (MAP_pD_pD::const_iterator it=reductionmaps[cid].begin();
it != reductionmaps[cid].end(); ++it)
*(it->first) = *(it->second);
}
}
void System::undoSolution()
@ -1239,7 +1303,7 @@ void System::undoSolution()
resetToReference();
}
int System::diagnose(VEC_pD &params, VEC_I &conflictingTags)
int System::diagnose()
{
// Analyses the constrainess grad of the system and provides feedback
// The vector "conflictingTags" will hold a group of conflicting constraints
@ -1251,22 +1315,24 @@ int System::diagnose(VEC_pD &params, VEC_I &conflictingTags)
// will provide no feedback about possible conflicts between
// two high priority constraints. For this reason, tagging
// constraints with 0 should be used carefully.
if (!isInit())
return -1;
hasDiagnosis = false;
if (!hasUnknowns) {
dofs = -1;
return dofs;
}
redundant.clear();
conflictingTags.clear();
std::vector<VEC_I> conflictingIndex;
VEC_I tags;
Eigen::MatrixXd J(clist.size(), params.size());
redundantTags.clear();
Eigen::MatrixXd J(clist.size(), plist.size());
int count=0;
for (std::vector<Constraint *>::iterator constr=clist.begin();
constr != clist.end(); ++constr) {
(*constr)->revertParams();
if ((*constr)->getTag() >= 0) {
count++;
tags.push_back((*constr)->getTag());
for (int j=0; j < int(params.size()); j++)
J(count-1,j) = (*constr)->grad(params[j]);
for (int j=0; j < int(plist.size()); j++)
J(count-1,j) = (*constr)->grad(plist[j]);
}
}
@ -1284,7 +1350,7 @@ int System::diagnose(VEC_pD &params, VEC_I &conflictingTags)
R = qrJT.matrixQR().topRows(constrNum)
.triangularView<Eigen::Upper>();
if (constrNum > rank) { // conflicting constraints
if (constrNum > rank) { // conflicting or redundant constraints
for (int i=1; i < rank; i++) {
// eliminate non zeros above pivot
assert(R(i,i) != 0);
@ -1296,43 +1362,142 @@ int System::diagnose(VEC_pD &params, VEC_I &conflictingTags)
}
}
}
conflictingIndex.resize(constrNum-rank);
std::vector< std::vector<Constraint *> > conflictGroups(constrNum-rank);
for (int j=rank; j < constrNum; j++) {
for (int row=0; row < rank; row++) {
if (fabs(R(row,j)) > 1e-10) {
int origCol = qrJT.colsPermutation().indices()[row];
conflictingIndex[j-rank].push_back(origCol);
conflictGroups[j-rank].push_back(clist[origCol]);
}
}
int origCol = qrJT.colsPermutation().indices()[j];
conflictingIndex[j-rank].push_back(origCol);
conflictGroups[j-rank].push_back(clist[origCol]);
}
SET_I tags_set;
for (int i=0; i < conflictingIndex.size(); i++) {
for (int j=0; j < conflictingIndex[i].size(); j++) {
tags_set.insert(tags[conflictingIndex[i][j]]);
// try to remove the conflicting constraints and solve the
// system in order to check if the removed constraints were
// just redundant but not really conflicting
std::set<Constraint *> skipped;
SET_I satisfiedGroups;
while (1) {
std::map< Constraint *, SET_I > conflictingMap;
for (int i=0; i < conflictGroups.size(); i++) {
if (satisfiedGroups.count(i) == 0) {
for (int j=0; j < conflictGroups[i].size(); j++) {
Constraint *constr = conflictGroups[i][j];
if (constr->getTag() != 0) // exclude constraints tagged with zero
conflictingMap[constr].insert(i);
}
}
}
if (conflictingMap.empty())
break;
int maxPopularity = 0;
Constraint *mostPopular = NULL;
for (std::map< Constraint *, SET_I >::const_iterator it=conflictingMap.begin();
it != conflictingMap.end(); it++) {
if (it->second.size() > maxPopularity ||
(it->second.size() == maxPopularity && mostPopular &&
it->first->getTag() > mostPopular->getTag())) {
mostPopular = it->first;
maxPopularity = it->second.size();
}
}
if (maxPopularity > 0) {
skipped.insert(mostPopular);
for (SET_I::const_iterator it=conflictingMap[mostPopular].begin();
it != conflictingMap[mostPopular].end(); it++)
satisfiedGroups.insert(*it);
}
}
tags_set.erase(0); // exclude constraints tagged with zero
conflictingTags.resize(tags_set.size());
std::copy(tags_set.begin(), tags_set.end(), conflictingTags.begin());
if (paramsNum == rank) // over-constrained
return paramsNum - constrNum;
std::vector<Constraint *> clistTmp;
clistTmp.reserve(clist.size());
for (std::vector<Constraint *>::iterator constr=clist.begin();
constr != clist.end(); ++constr)
if (skipped.count(*constr) == 0)
clistTmp.push_back(*constr);
SubSystem *subSysTmp = new SubSystem(clistTmp, plist);
int res = solve(subSysTmp);
if (res == Success) {
subSysTmp->applySolution();
for (std::set<Constraint *>::const_iterator constr=skipped.begin();
constr != skipped.end(); constr++) {
double err = (*constr)->error();
if (err * err < XconvergenceFine)
redundant.insert(*constr);
}
resetToReference();
std::vector< std::vector<Constraint *> > conflictGroupsOrig=conflictGroups;
conflictGroups.clear();
for (int i=conflictGroupsOrig.size()-1; i >= 0; i--) {
bool isRedundant = false;
for (int j=0; j < conflictGroupsOrig[i].size(); j++) {
if (redundant.count(conflictGroupsOrig[i][j]) > 0) {
isRedundant = true;
break;
}
}
if (!isRedundant)
conflictGroups.push_back(conflictGroupsOrig[i]);
else
constrNum--;
}
}
delete subSysTmp;
// simplified output of conflicting tags
SET_I conflictingTagsSet;
for (int i=0; i < conflictGroups.size(); i++) {
for (int j=0; j < conflictGroups[i].size(); j++) {
conflictingTagsSet.insert(conflictGroups[i][j]->getTag());
}
}
conflictingTagsSet.erase(0); // exclude constraints tagged with zero
conflictingTags.resize(conflictingTagsSet.size());
std::copy(conflictingTagsSet.begin(), conflictingTagsSet.end(),
conflictingTags.begin());
// output of redundant tags
SET_I redundantTagsSet;
for (std::set<Constraint *>::iterator constr=redundant.begin();
constr != redundant.end(); ++constr)
redundantTagsSet.insert((*constr)->getTag());
// remove tags represented at least in one non-redundant constraint
for (std::vector<Constraint *>::iterator constr=clist.begin();
constr != clist.end(); ++constr)
if (redundant.count(*constr) == 0)
redundantTagsSet.erase((*constr)->getTag());
redundantTags.resize(redundantTagsSet.size());
std::copy(redundantTagsSet.begin(), redundantTagsSet.end(),
redundantTags.begin());
if (paramsNum == rank && constrNum > rank) { // over-constrained
hasDiagnosis = true;
dofs = paramsNum - constrNum;
return dofs;
}
}
return paramsNum - rank;
hasDiagnosis = true;
dofs = paramsNum - rank;
return dofs;
}
return params.size();
hasDiagnosis = true;
dofs = plist.size();
return dofs;
}
void System::clearSubSystems()
{
init = false;
for (int i=0; i < int(subsyslist.size()); i++)
free(subsyslist[i]);
subsyslist.clear();
isInit = false;
free(subSystems);
free(subSystemsAux);
subSystems.clear();
subSystemsAux.clear();
}
double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir)

View File

@ -49,25 +49,31 @@ namespace GCS
// This is the main class. It holds all constraints and information
// about partitioning into subsystems and solution strategies
private:
std::vector<Constraint *> clist;
VEC_pD plist; // list of the unknown parameters
MAP_pD_I pIndex;
std::vector<Constraint *> clist;
std::map<Constraint *,VEC_pD > c2p; // constraint to parameter adjacency list
std::map<double *,std::vector<Constraint *> > p2c; // parameter to constraint adjacency list
// each row of subsyslist contains up to 3 subsystems.
// the first one has the highest priority, always used as the primary subsystem
// the second one is used as secondary subsystem
// the third one is used as secondary system and serves as a preconditioner
std::vector< std::vector<SubSystem *> > subsyslist;
std::vector<SubSystem *> subSystems, subSystemsAux;
void clearSubSystems();
MAP_pD_D reference;
void clearReference();
void resetToReference();
VEC_D reference;
void setReference(); // copies the current parameter values to reference
void resetToReference(); // reverts all parameter values to the stored reference
MAP_pD_pD reductionmap; // for simplification of equality constraints
std::vector< VEC_pD > plists; // partitioned plist except equality constraints
std::vector< std::vector<Constraint *> > clists; // partitioned clist except equality constraints
std::vector< MAP_pD_pD > reductionmaps; // for simplification of equality constraints
bool init;
int dofs;
std::set<Constraint *> redundant;
VEC_I conflictingTags, redundantTags;
bool hasUnknowns; // if plist is filled with the unknown parameters
bool hasDiagnosis; // if dofs, conflictingTags, redundantTags are up to date
bool isInit; // if plists, clists, reductionmaps are up to date
int solve_BFGS(SubSystem *subsys, bool isFine);
int solve_LM(SubSystem *subsys);
@ -147,7 +153,8 @@ namespace GCS
int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0);
void rescaleConstraint(int id, double coeff);
void initSolution(VEC_pD &params);
void declareUnknowns(VEC_pD &params);
void initSolution();
int solve(bool isFine=true, Algorithm alg=DogLeg);
int solve(VEC_pD &params, bool isFine=true, Algorithm alg=DogLeg);
@ -157,9 +164,12 @@ namespace GCS
void applySolution();
void undoSolution();
bool isInit() const { return init; }
int diagnose(VEC_pD &params, VEC_I &conflictingTags);
int diagnose();
int dofsNumber() { return hasDiagnosis ? dofs : -1; }
void getConflicting(VEC_I &conflictingOut) const
{ conflictingOut = hasDiagnosis ? conflictingTags : VEC_I(0); }
void getRedundant(VEC_I &redundantOut) const
{ redundantOut = hasDiagnosis ? redundantTags : VEC_I(0); }
};
///////////////////////////////////////

View File

@ -54,8 +54,8 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView)
this->groupLayout()->addWidget(proxy);
connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1,_2,_3));
connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1,_2));
connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1));
connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1));
}
TaskSketcherMessages::~TaskSketcherMessages()
@ -65,43 +65,14 @@ TaskSketcherMessages::~TaskSketcherMessages()
delete ui;
}
void TaskSketcherMessages::slotSetUp(int type, int dofs, const std::string &msg)
void TaskSketcherMessages::slotSetUp(QString msg)
{
switch(type){
case -1:
ui->labelConstrainStatus->setText(QString::fromLatin1("Empty sketch"));
break;
case 0:
ui->labelConstrainStatus->setText(QString::fromLatin1("<font color='green'>Fully constrained sketch </font>"));
break;
case 1:
if (dofs==1)
ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom"));
else
ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs));
break;
case 2:
ui->labelConstrainStatus->setText(QString::fromLatin1("<font color='red'>Sketch contains conflicting constraints<br/>%1</font>").arg(QString::fromStdString(msg)));
break;
case 3:
ui->labelConstrainStatus->setText(QString::fromLatin1("<font color='red'>Over-constrained sketch<br/>%1</font>").arg(QString::fromStdString(msg)));
break;
}
ui->labelConstrainStatus->setText(msg);
}
void TaskSketcherMessages::slotSolved(int type, float time)
void TaskSketcherMessages::slotSolved(QString msg)
{
switch(type){
case -1:
ui->labelSolverStatus->setText(QString());
break;
case 0:
ui->labelSolverStatus->setText(QString::fromLatin1("Solved in %1 sec").arg(time));
break;
case 1:
ui->labelSolverStatus->setText(QString::fromLatin1("Unsolved (%1)").arg(time));
break;
}
ui->labelSolverStatus->setText(msg);
}
#include "moc_TaskSketcherMessages.cpp"

View File

@ -47,8 +47,8 @@ public:
TaskSketcherMessages(ViewProviderSketch *sketchView);
~TaskSketcherMessages();
void slotSetUp(int type, int dofs, const std::string &msg);
void slotSolved(int type, float time);
void slotSetUp(QString msg);
void slotSolved(QString msg);
private Q_SLOTS:

View File

@ -768,7 +768,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
int GeoId;
Sketcher::PointPos PosId;
getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId);
edit->ActSketch.initMove(GeoId, PosId);
edit->ActSketch.initMove(GeoId, PosId, false);
relative = false;
xInit = 0;
yInit = 0;
@ -785,7 +785,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) {
Mode = STATUS_SKETCH_DragCurve;
edit->DragCurve = edit->PreselectCurve;
edit->ActSketch.initMove(edit->DragCurve, Sketcher::none);
edit->ActSketch.initMove(edit->DragCurve, Sketcher::none, false);
const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve);
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
relative = true;
@ -822,9 +822,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) {
setPositionText(Base::Vector2D(x,y));
draw(true);
signalSolved(0, edit->ActSketch.SolveTime);
signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
} else {
signalSolved(1, edit->ActSketch.SolveTime);
signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime));
//Base::Console().Log("Error solving:%d\n",ret);
}
}
@ -835,9 +835,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) {
setPositionText(Base::Vector2D(x,y));
draw(true);
signalSolved(0, edit->ActSketch.SolveTime);
signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
} else {
signalSolved(1, edit->ActSketch.SolveTime);
signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime));
}
}
return true;
@ -2694,42 +2694,7 @@ void ViewProviderSketch::updateData(const App::Property *prop)
if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) {
edit->FullyConstrained = false;
int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(),
getSketchObject()->Constraints.getValues(),
true, getSketchObject()->getExternalGeometryCount());
std::string msg;
if (getSketchObject()->Geometry.getSize() == 0) {
signalSetUp(-1, 0, msg);
signalSolved(-1, 0);
}
else if (dofs < 0) { // over-constrained sketch
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
//Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str());
signalSetUp(3, 0, msg);
signalSolved(-1,0);
}
else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
//Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str());
signalSetUp(2, dofs, msg);
signalSolved(-1,0);
}
else if (edit->ActSketch.solve() == 0) { // solving the sketch
if (dofs == 0) {
// color the sketch as fully constrained
edit->FullyConstrained = true;
//Base::Console().Message("Fully constrained sketch\n");
signalSetUp(0, 0, msg);
}
else {
//Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs);
signalSetUp(1, dofs, msg);
}
signalSolved(0,edit->ActSketch.SolveTime);
}
else {
signalSolved(1,edit->ActSketch.SolveTime);
}
solveSketch();
draw(true);
}
if (edit && &(getSketchObject()->Constraints)) {
@ -2831,49 +2796,64 @@ bool ViewProviderSketch::setEdit(int ModNum)
else
Gui::Control().showDialog(new TaskDlgEditSketch(this));
// set up the sketch and diagnose possible conflicts
int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(),
getSketchObject()->Constraints.getValues(),
true, getSketchObject()->getExternalGeometryCount());
std::string msg;
if (getSketchObject()->Geometry.getSize() == 0) {
signalSetUp(-1, 0, msg);
signalSolved(-1, 0);
}
else if (dofs < 0) { // over-constrained sketch
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
//Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str());
signalSetUp(3, 0, msg);
signalSolved(-1, 0);
}
else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
//Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str());
signalSetUp(2, dofs, msg);
signalSolved(-1, 0);
}
else if (edit->ActSketch.solve() == 0) { // solving the sketch
if (dofs == 0) {
// color the sketch as fully constrained
edit->FullyConstrained = true;
//Base::Console().Message("Fully constrained sketch\n");
signalSetUp(0, 0, msg);
}
else {
//Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs);
signalSetUp(1, dofs, msg);
}
signalSolved(0, edit->ActSketch.SolveTime);
}
else {
signalSolved(1, edit->ActSketch.SolveTime);
}
solveSketch();
draw();
return true;
}
void ViewProviderSketch::solveSketch(void)
{
// set up the sketch and diagnose possible conflicts
int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(),
getSketchObject()->Constraints.getValues(),
getSketchObject()->getExternalGeometryCount());
if (getSketchObject()->Geometry.getSize() == 0) {
signalSetUp(QString::fromLatin1("Empty sketch"));
signalSolved(QString());
}
else if (dofs < 0) { // over-constrained sketch
std::string msg;
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
signalSetUp(QString::fromLatin1("<font color='red'>Over-constrained sketch<br/>%1</font>")
.arg(QString::fromStdString(msg)));
signalSolved(QString());
}
else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
std::string msg;
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
signalSetUp(QString::fromLatin1("<font color='red'>Sketch contains conflicting constraints<br/>%1</font>")
.arg(QString::fromStdString(msg)));
signalSolved(QString());
}
else {
if (edit->ActSketch.hasRedundancies()) { // redundant constraints
std::string msg;
SketchObject::appendRedundantMsg(edit->ActSketch.getRedundant(), msg);
signalSetUp(QString::fromLatin1("<font color='orange'>Sketch contains redundant constraints<br/>%1</font>")
.arg(QString::fromStdString(msg)));
}
if (edit->ActSketch.solve() == 0) { // solving the sketch
if (dofs == 0) {
// color the sketch as fully constrained
edit->FullyConstrained = true;
if (!edit->ActSketch.hasRedundancies())
signalSetUp(QString::fromLatin1("<font color='green'>Fully constrained sketch </font>"));
}
else if (!edit->ActSketch.hasRedundancies()) {
if (dofs == 1)
signalSetUp(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom"));
else
signalSetUp(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs));
}
signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
}
else {
signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime));
}
}
}
void ViewProviderSketch::createEditInventorNodes(void)
{
assert(edit);

View File

@ -174,15 +174,17 @@ public:
/// signals if the constraints list has changed
boost::signal<void ()> signalConstraintsChanged;
/// signals if the sketch has been set up
boost::signal<void (int type, int dofs, std::string &msg)> signalSetUp;
boost::signal<void (QString msg)> signalSetUp;
/// signals if the sketch has been solved
boost::signal<void (int type, float time)> signalSolved;
boost::signal<void (QString msg)> signalSolved;
protected:
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
virtual void setEditViewer(Gui::View3DInventorViewer*, int ModNum);
virtual void unsetEditViewer(Gui::View3DInventorViewer*);
/// set up and solve the sketch
void solveSketch(void);
/// helper to detect whether the picked point lies on the sketch
bool isPointOnSketch(const SoPickedPoint *pp) const;
/// get called by the container whenever a property has been changed