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

View File

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

View File

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

View File

@ -136,6 +136,8 @@ public:
/// generates a warning message about constraint conflicts and appends it to the given message /// 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); 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 // from base class
virtual PyObject *getPyObject(void); virtual PyObject *getPyObject(void);

View File

@ -41,19 +41,20 @@ typedef boost::adjacency_list <boost::vecS, boost::vecS, boost::undirectedS> Gra
// System // System
System::System() System::System()
: clist(0), : plist(0), clist(0),
c2p(), p2c(), c2p(), p2c(),
subsyslist(0), subSystems(0), subSystemsAux(0),
reference(), reference(0),
init(false) hasUnknowns(false), hasDiagnosis(false), isInit(false)
{ {
} }
System::System(std::vector<Constraint *> clist_) System::System(std::vector<Constraint *> clist_)
: c2p(), p2c(), : plist(0),
subsyslist(0), c2p(), p2c(),
reference(), subSystems(0), subSystemsAux(0),
init(false) reference(0),
hasUnknowns(false), hasDiagnosis(false), isInit(false)
{ {
// create own (shallow) copy of constraints // create own (shallow) copy of constraints
for (std::vector<Constraint *>::iterator constr=clist_.begin(); for (std::vector<Constraint *>::iterator constr=clist_.begin();
@ -125,7 +126,16 @@ System::~System()
void System::clear() void System::clear()
{ {
clearReference(); plist.clear();
pIndex.clear();
hasUnknowns = false;
hasDiagnosis = false;
redundant.clear();
conflictingTags.clear();
redundantTags.clear();
reference.clear();
clearSubSystems(); clearSubSystems();
free(clist); free(clist);
c2p.clear(); c2p.clear();
@ -148,7 +158,9 @@ void System::clearByTag(int tagId)
int System::addConstraint(Constraint *constr) 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); clist.push_back(constr);
VEC_pD constr_params = constr->params(); VEC_pD constr_params = constr->params();
@ -163,12 +175,15 @@ int System::addConstraint(Constraint *constr)
void System::removeConstraint(Constraint *constr) void System::removeConstraint(Constraint *constr)
{ {
clearReference();
clearSubSystems();
std::vector<Constraint *>::iterator it; std::vector<Constraint *>::iterator it;
it = std::find(clist.begin(), clist.end(), constr); it = std::find(clist.begin(), clist.end(), constr);
if (it == clist.end())
return;
clist.erase(it); clist.erase(it);
if (constr->getTag() >= 0)
hasDiagnosis = false;
clearSubSystems();
VEC_pD constr_params = c2p[constr]; VEC_pD constr_params = c2p[constr];
for (VEC_pD::const_iterator param=constr_params.begin(); for (VEC_pD::const_iterator param=constr_params.begin();
@ -545,9 +560,18 @@ void System::rescaleConstraint(int id, double coeff)
clist[id]->rescale(coeff); clist[id]->rescale(coeff);
} }
void System::declareUnknowns(VEC_pD &params)
void System::initSolution(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 // - identifies any decoupled subsystems and partitions the original
// system into corresponding components // system into corresponding components
// - Stores the current parameters in the vector "reference" // - 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 // - Organizes the rest of constraints into two subsystems for
// tag ids >=0 and < 0 respectively and applies the // tag ids >=0 and < 0 respectively and applies the
// system reduction specified in the previous step // system reduction specified in the previous step
MAP_pD_I pIndex;
for (int i=0; i < int(params.size()); ++i) isInit = false;
pIndex[params[i]] = i; 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 // partitioning into decoupled components
Graph g; 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); boost::add_vertex(g);
int cvtid = int(params.size()); int cvtid = int(plist.size());
for (std::vector<Constraint *>::const_iterator constr=clist.begin(); for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
constr != clist.end(); ++constr, cvtid++) { constr != clistR.end(); ++constr, cvtid++) {
VEC_pD &cparams = c2p[*constr]; VEC_pD &cparams = c2p[*constr];
for (VEC_pD::const_iterator param=cparams.begin(); for (VEC_pD::const_iterator param=cparams.begin();
param != cparams.end(); ++param) { param != cparams.end(); ++param) {
@ -580,113 +624,131 @@ void System::initSolution(VEC_pD &params)
VEC_I components(boost::num_vertices(g)); VEC_I components(boost::num_vertices(g));
int componentsSize = boost::connected_components(g, &components[0]); 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 // identification of equality constraints and parameter reduction
std::set<Constraint *> eliminated; // constraints that will be eliminated through reduction std::set<Constraint *> reducedConstrs; // constraints that will be eliminated through reduction
reductionmap.clear(); 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(); for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
constr != clist.end(); ++constr) { constr != clistR.end(); ++constr) {
if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) { if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) {
MAP_pD_I::const_iterator it1,it2; MAP_pD_I::const_iterator it1,it2;
it1 = pIndex.find((*constr)->params()[0]); it1 = pIndex.find((*constr)->params()[0]);
it2 = pIndex.find((*constr)->params()[1]); it2 = pIndex.find((*constr)->params()[1]);
if (it1 != pIndex.end() && it2 != pIndex.end()) { if (it1 != pIndex.end() && it2 != pIndex.end()) {
eliminated.insert(*constr); reducedConstrs.insert(*constr);
double *p_kept = reduced_params[it1->second]; double *p_kept = reducedParams[it1->second];
double *p_replaced = reduced_params[it2->second]; double *p_replaced = reducedParams[it2->second];
for (int i=0; i < int(params.size()); ++i) for (int i=0; i < int(plist.size()); ++i)
if (reduced_params[i] == p_replaced) if (reducedParams[i] == p_replaced)
reduced_params[i] = p_kept; reducedParams[i] = p_kept;
} }
} }
} }
for (int i=0; i < int(params.size()); ++i) for (int i=0; i < int(plist.size()); ++i)
if (params[i] != reduced_params[i]) if (plist[i] != reducedParams[i]) {
reductionmap[params[i]] = reduced_params[i]; int cid = components[i];
reductionmaps[cid][plist[i]] = reducedParams[i];
}
} }
std::vector< std::vector<Constraint *> > clists0(componentsSize), clists.clear(); // destroy any lists
clists1(componentsSize), clists.resize(componentsSize); // create empty lists to be filled in
clists2(componentsSize); int i = int(plist.size());
int i = int(params.size()); for (std::vector<Constraint *>::const_iterator constr=clistR.begin();
for (std::vector<Constraint *>::const_iterator constr=clist.begin(); constr != clistR.end(); ++constr, i++) {
constr != clist.end(); ++constr, i++) { if (reducedConstrs.count(*constr) == 0) {
if (eliminated.count(*constr) == 0) { int cid = components[i];
int id = components[i]; clists[cid].push_back(*constr);
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);
} }
} }
std::vector< std::vector<double *> > plists(componentsSize); plists.clear(); // destroy any lists
for (int i=0; i < int(params.size()); ++i) { plists.resize(componentsSize); // create empty lists to be filled in
int id = components[i]; for (int i=0; i < int(plist.size()); ++i) {
plists[id].push_back(params[i]); int cid = components[i];
plists[cid].push_back(plist[i]);
} }
// calculates subSystems and subSystemsAux from clists, plists and reductionmaps
clearSubSystems(); clearSubSystems();
for (int cid=0; cid < componentsSize; cid++) { for (int cid=0; cid < clists.size(); cid++) {
subsyslist.push_back(std::vector<SubSystem *>(0)); std::vector<Constraint *> clist0, clist1;
if (clists0[cid].size() > 0) for (std::vector<Constraint *>::const_iterator constr=clists[cid].begin();
subsyslist[cid].push_back(new SubSystem(clists0[cid], plists[cid], reductionmap)); constr != clists[cid].end(); ++constr) {
if (clists1[cid].size() > 0) if ((*constr)->getTag() >= 0)
subsyslist[cid].push_back(new SubSystem(clists1[cid], plists[cid], reductionmap)); clist0.push_back(*constr);
if (clists2[cid].size() > 0) else // move or distance from reference constraints
subsyslist[cid].push_back(new SubSystem(clists2[cid], plists[cid], reductionmap)); 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.clear();
reference.reserve(plist.size());
for (VEC_pD::const_iterator param=plist.begin();
param != plist.end(); ++param)
reference.push_back(**param);
} }
void System::resetToReference() void System::resetToReference()
{ {
for (MAP_pD_D::const_iterator it=reference.begin(); if (reference.size() == plist.size()) {
it != reference.end(); ++it) VEC_D::const_iterator ref=reference.begin();
*(it->first) = it->second; VEC_pD::iterator param=plist.begin();
for (; ref != reference.end(); ++ref, ++param)
**param = *ref;
}
} }
int System::solve(VEC_pD &params, bool isFine, Algorithm alg) int System::solve(VEC_pD &params, bool isFine, Algorithm alg)
{ {
initSolution(params); declareUnknowns(params);
initSolution();
return solve(isFine, alg); return solve(isFine, alg);
} }
int System::solve(bool isFine, Algorithm alg) int System::solve(bool isFine, Algorithm alg)
{ {
if (!isInit)
return Failed;
bool isReset = false; bool isReset = false;
// return success by default in order to permit coincidence constraints to be applied // return success by default in order to permit coincidence constraints to be applied
// even if no other system has to be solved // even if no other system has to be solved
int res = Success; int res = Success;
for (int cid=0; cid < int(subsyslist.size()); cid++) { for (int cid=0; cid < int(subSystems.size()); cid++) {
if (subsyslist[cid].size() > 0 && !isReset) { if ((subSystems[cid] || subSystemsAux[cid]) && !isReset) {
resetToReference(); resetToReference();
isReset = true; isReset = true;
} }
if (subsyslist[cid].size() == 1) if (subSystems[cid] && subSystemsAux[cid])
res = std::max(res, solve(subsyslist[cid][0], isFine, alg)); res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine));
else if (subsyslist[cid].size() == 2) else if (subSystems[cid])
res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][1], isFine)); res = std::max(res, solve(subSystems[cid], isFine, alg));
else if (subsyslist[cid].size() > 2) else if (subSystemsAux[cid])
// subsystem 1 has higher priority than subsystems 2,3,... res = std::max(res, solve(subSystemsAux[cid], isFine, alg));
// these subsystems act like a preconditioner }
for (int i=subsyslist[cid].size()-1; i > 0; i--) if (res == Success) {
res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][i], isFine)); for (std::set<Constraint *>::const_iterator constr=redundant.begin();
constr != redundant.end(); constr++)
if ((*constr)->error() > XconvergenceFine) {
res = Converged;
return res;
}
} }
return res; return res;
} }
@ -1068,7 +1130,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
int xsizeB = subsysB->pSize(); int xsizeB = subsysB->pSize();
int csizeA = subsysA->cSize(); int csizeA = subsysA->cSize();
VEC_pD plist(xsizeA+xsizeB); VEC_pD plistAB(xsizeA+xsizeB);
{ {
VEC_pD plistA, plistB; VEC_pD plistA, plistB;
subsysA->getParamList(plistA); subsysA->getParamList(plistA);
@ -1079,10 +1141,10 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
VEC_pD::const_iterator it; VEC_pD::const_iterator it;
it = std::set_union(plistA.begin(),plistA.end(), it = std::set_union(plistA.begin(),plistA.end(),
plistB.begin(),plistB.end(),plist.begin()); plistB.begin(),plistB.end(),plistAB.begin());
plist.resize(it-plist.begin()); plistAB.resize(it-plistAB.begin());
} }
int xsize = plist.size(); int xsize = plistAB.size();
Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize); Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize);
Eigen::MatrixXd JA(csizeA, xsize); Eigen::MatrixXd JA(csizeA, xsize);
@ -1100,12 +1162,12 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
subsysA->redirectParams(); subsysA->redirectParams();
subsysB->redirectParams(); subsysB->redirectParams();
subsysB->getParams(plist,x); subsysB->getParams(plistAB,x);
subsysA->getParams(plist,x); subsysA->getParams(plistAB,x);
subsysB->setParams(plist,x); // just to ensure that A and B are synchronized subsysB->setParams(plistAB,x); // just to ensure that A and B are synchronized
subsysB->calcGrad(plist,grad); subsysB->calcGrad(plistAB,grad);
subsysA->calcJacobi(plist,JA); subsysA->calcJacobi(plistAB,JA);
subsysA->calcResidual(resA); subsysA->calcResidual(resA);
double convergence = isFine ? XconvergenceFine : XconvergenceRough; double convergence = isFine ? XconvergenceFine : XconvergenceRough;
@ -1130,7 +1192,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine)
double tau=0.5; double tau=0.5;
double rho=0.5; double rho=0.5;
double alpha=1; double alpha=1;
alpha = std::min(alpha, subsysA->maxStep(plist,xdir)); alpha = std::min(alpha, subsysA->maxStep(plistAB,xdir));
// Eq. 18.32 // Eq. 18.32
// double mu = lambda.lpNorm<Eigen::Infinity>() + 0.01; // 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>(); double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>();
x = x0 + alpha * xdir; x = x0 + alpha * xdir;
subsysA->setParams(plist,x); subsysA->setParams(plistAB,x);
subsysB->setParams(plist,x); subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA); subsysA->calcResidual(resA);
double f = subsysB->error() + mu * resA.lpNorm<1>(); 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); // Eigen::ComputeThinV).solve(-resA);
xdir1 = -Y*resA; xdir1 = -Y*resA;
x += xdir1; // = x0 + alpha * xdir + xdir1 x += xdir1; // = x0 + alpha * xdir + xdir1
subsysA->setParams(plist,x); subsysA->setParams(plistAB,x);
subsysB->setParams(plist,x); subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA); subsysA->calcResidual(resA);
f = subsysB->error() + mu * resA.lpNorm<1>(); f = subsysB->error() + mu * resA.lpNorm<1>();
if (f < f0 + eta * alpha * deriv) 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 if (alpha < 1e-8) // let the linesearch fail
alpha = 0.; alpha = 0.;
x = x0 + alpha * xdir; x = x0 + alpha * xdir;
subsysA->setParams(plist,x); subsysA->setParams(plistAB,x);
subsysB->setParams(plist,x); subsysB->setParams(plistAB,x);
subsysA->calcResidual(resA); subsysA->calcResidual(resA);
f = subsysB->error() + mu * resA.lpNorm<1>(); f = subsysB->error() + mu * resA.lpNorm<1>();
if (alpha < 1e-8) // let the linesearch fail 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; y = grad - JA.transpose() * lambda;
{ {
subsysB->calcGrad(plist,grad); subsysB->calcGrad(plistAB,grad);
subsysA->calcJacobi(plist,JA); subsysA->calcJacobi(plistAB,JA);
subsysA->calcResidual(resA); subsysA->calcResidual(resA);
} }
y = grad - JA.transpose() * lambda - y; // Eq. 18.13 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() void System::applySolution()
{ {
for (int cid=0; cid < int(subsyslist.size()); cid++) for (int cid=0; cid < int(subSystems.size()); cid++) {
for (int i=subsyslist[cid].size()-1; i >= 0; i--) if (subSystemsAux[cid])
subsyslist[cid][i]->applySolution(); subSystemsAux[cid]->applySolution();
if (subSystems[cid])
for (MAP_pD_pD::const_iterator it=reductionmap.begin(); subSystems[cid]->applySolution();
it != reductionmap.end(); ++it) for (MAP_pD_pD::const_iterator it=reductionmaps[cid].begin();
*(it->first) = *(it->second); it != reductionmaps[cid].end(); ++it)
*(it->first) = *(it->second);
}
} }
void System::undoSolution() void System::undoSolution()
@ -1239,7 +1303,7 @@ void System::undoSolution()
resetToReference(); resetToReference();
} }
int System::diagnose(VEC_pD &params, VEC_I &conflictingTags) int System::diagnose()
{ {
// Analyses the constrainess grad of the system and provides feedback // Analyses the constrainess grad of the system and provides feedback
// The vector "conflictingTags" will hold a group of conflicting constraints // 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 // will provide no feedback about possible conflicts between
// two high priority constraints. For this reason, tagging // two high priority constraints. For this reason, tagging
// constraints with 0 should be used carefully. // constraints with 0 should be used carefully.
if (!isInit()) hasDiagnosis = false;
return -1; if (!hasUnknowns) {
dofs = -1;
return dofs;
}
redundant.clear();
conflictingTags.clear(); conflictingTags.clear();
std::vector<VEC_I> conflictingIndex; redundantTags.clear();
VEC_I tags; Eigen::MatrixXd J(clist.size(), plist.size());
Eigen::MatrixXd J(clist.size(), params.size());
int count=0; int count=0;
for (std::vector<Constraint *>::iterator constr=clist.begin(); for (std::vector<Constraint *>::iterator constr=clist.begin();
constr != clist.end(); ++constr) { constr != clist.end(); ++constr) {
(*constr)->revertParams(); (*constr)->revertParams();
if ((*constr)->getTag() >= 0) { if ((*constr)->getTag() >= 0) {
count++; count++;
tags.push_back((*constr)->getTag()); for (int j=0; j < int(plist.size()); j++)
for (int j=0; j < int(params.size()); j++) J(count-1,j) = (*constr)->grad(plist[j]);
J(count-1,j) = (*constr)->grad(params[j]);
} }
} }
@ -1284,7 +1350,7 @@ int System::diagnose(VEC_pD &params, VEC_I &conflictingTags)
R = qrJT.matrixQR().topRows(constrNum) R = qrJT.matrixQR().topRows(constrNum)
.triangularView<Eigen::Upper>(); .triangularView<Eigen::Upper>();
if (constrNum > rank) { // conflicting constraints if (constrNum > rank) { // conflicting or redundant constraints
for (int i=1; i < rank; i++) { for (int i=1; i < rank; i++) {
// eliminate non zeros above pivot // eliminate non zeros above pivot
assert(R(i,i) != 0); 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 j=rank; j < constrNum; j++) {
for (int row=0; row < rank; row++) { for (int row=0; row < rank; row++) {
if (fabs(R(row,j)) > 1e-10) { if (fabs(R(row,j)) > 1e-10) {
int origCol = qrJT.colsPermutation().indices()[row]; 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]; int origCol = qrJT.colsPermutation().indices()[j];
conflictingIndex[j-rank].push_back(origCol); conflictGroups[j-rank].push_back(clist[origCol]);
} }
SET_I tags_set; // try to remove the conflicting constraints and solve the
for (int i=0; i < conflictingIndex.size(); i++) { // system in order to check if the removed constraints were
for (int j=0; j < conflictingIndex[i].size(); j++) { // just redundant but not really conflicting
tags_set.insert(tags[conflictingIndex[i][j]]); 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 std::vector<Constraint *> clistTmp;
return paramsNum - constrNum; 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() void System::clearSubSystems()
{ {
init = false; isInit = false;
for (int i=0; i < int(subsyslist.size()); i++) free(subSystems);
free(subsyslist[i]); free(subSystemsAux);
subsyslist.clear(); subSystems.clear();
subSystemsAux.clear();
} }
double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir) 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 // This is the main class. It holds all constraints and information
// about partitioning into subsystems and solution strategies // about partitioning into subsystems and solution strategies
private: 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<Constraint *,VEC_pD > c2p; // constraint to parameter adjacency list
std::map<double *,std::vector<Constraint *> > p2c; // parameter to constraint adjacency list std::map<double *,std::vector<Constraint *> > p2c; // parameter to constraint adjacency list
// each row of subsyslist contains up to 3 subsystems. std::vector<SubSystem *> subSystems, subSystemsAux;
// 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;
void clearSubSystems(); void clearSubSystems();
MAP_pD_D reference; VEC_D reference;
void clearReference(); void setReference(); // copies the current parameter values to reference
void resetToReference(); 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_BFGS(SubSystem *subsys, bool isFine);
int solve_LM(SubSystem *subsys); int solve_LM(SubSystem *subsys);
@ -147,7 +153,8 @@ namespace GCS
int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0);
void rescaleConstraint(int id, double coeff); 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(bool isFine=true, Algorithm alg=DogLeg);
int solve(VEC_pD &params, 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 applySolution();
void undoSolution(); void undoSolution();
bool isInit() const { return init; } int diagnose();
int dofsNumber() { return hasDiagnosis ? dofs : -1; }
int diagnose(VEC_pD &params, VEC_I &conflictingTags); 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); this->groupLayout()->addWidget(proxy);
connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1,_2,_3)); connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1));
connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1,_2)); connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1));
} }
TaskSketcherMessages::~TaskSketcherMessages() TaskSketcherMessages::~TaskSketcherMessages()
@ -65,43 +65,14 @@ TaskSketcherMessages::~TaskSketcherMessages()
delete ui; delete ui;
} }
void TaskSketcherMessages::slotSetUp(int type, int dofs, const std::string &msg) void TaskSketcherMessages::slotSetUp(QString msg)
{ {
switch(type){ ui->labelConstrainStatus->setText(msg);
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;
}
} }
void TaskSketcherMessages::slotSolved(int type, float time) void TaskSketcherMessages::slotSolved(QString msg)
{ {
switch(type){ ui->labelSolverStatus->setText(msg);
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;
}
} }
#include "moc_TaskSketcherMessages.cpp" #include "moc_TaskSketcherMessages.cpp"

View File

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

View File

@ -768,7 +768,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
int GeoId; int GeoId;
Sketcher::PointPos PosId; Sketcher::PointPos PosId;
getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId);
edit->ActSketch.initMove(GeoId, PosId); edit->ActSketch.initMove(GeoId, PosId, false);
relative = false; relative = false;
xInit = 0; xInit = 0;
yInit = 0; yInit = 0;
@ -785,7 +785,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) { edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) {
Mode = STATUS_SKETCH_DragCurve; Mode = STATUS_SKETCH_DragCurve;
edit->DragCurve = edit->PreselectCurve; 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); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve);
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
relative = true; relative = true;
@ -822,9 +822,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal,
if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) { if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) {
setPositionText(Base::Vector2D(x,y)); setPositionText(Base::Vector2D(x,y));
draw(true); draw(true);
signalSolved(0, edit->ActSketch.SolveTime); signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
} else { } else {
signalSolved(1, edit->ActSketch.SolveTime); signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime));
//Base::Console().Log("Error solving:%d\n",ret); //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) { if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) {
setPositionText(Base::Vector2D(x,y)); setPositionText(Base::Vector2D(x,y));
draw(true); draw(true);
signalSolved(0, edit->ActSketch.SolveTime); signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
} else { } else {
signalSolved(1, edit->ActSketch.SolveTime); signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime));
} }
} }
return true; return true;
@ -2694,42 +2694,7 @@ void ViewProviderSketch::updateData(const App::Property *prop)
if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) { if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) {
edit->FullyConstrained = false; edit->FullyConstrained = false;
int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), solveSketch();
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);
}
draw(true); draw(true);
} }
if (edit && &(getSketchObject()->Constraints)) { if (edit && &(getSketchObject()->Constraints)) {
@ -2831,49 +2796,64 @@ bool ViewProviderSketch::setEdit(int ModNum)
else else
Gui::Control().showDialog(new TaskDlgEditSketch(this)); Gui::Control().showDialog(new TaskDlgEditSketch(this));
// set up the sketch and diagnose possible conflicts solveSketch();
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);
}
draw(); draw();
return true; 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) void ViewProviderSketch::createEditInventorNodes(void)
{ {
assert(edit); assert(edit);

View File

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