Sketcher new feature: Select Conflict and Redundant Constraints

Based (and solves) Mantis ticket:
http://www.freecadweb.org/tracker/view.php?id=1643

The ticket refers only to redundant, and ask for deletion.

Two commands are created, one for redundant constraints and other for conflicting constraints.

As usually removing one constraint of the "at least one" is sufficient, the implementation selects the constraints (but does not delete them).

The user therefore easily identify the constraints involved and decide to delete them.

This implementation takes into account the edit->Actsketch that ViewProvidedSketch creates for solving, as it is this instance the one that generates the messages in the Sketcher Taskbar.

No buttons in the toolbar by default (can be added by the user), but an hyperlink in the solver messages which triggers the selection of the appropriate command (conflicting or redundant).
This commit is contained in:
Abdullah Tahiri 2014-08-29 17:01:10 +02:00 committed by wmayer
parent bdbf5140f9
commit 34cc7c3136
7 changed files with 165 additions and 14 deletions

View File

@ -108,6 +108,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void)
} }
Sketch sketch; Sketch sketch;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
getExternalGeometryCount()); getExternalGeometryCount());
if (dofs < 0) { // over-constrained sketch if (dofs < 0) { // over-constrained sketch

View File

@ -448,6 +448,114 @@ bool CmdSketcherSelectHorizontalAxis::isActive(void)
return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); return isSketcherAcceleratorActive( getActiveGuiDocument(), false );
} }
DEF_STD_CMD_A(CmdSketcherSelectRedundantConstraints);
CmdSketcherSelectRedundantConstraints::CmdSketcherSelectRedundantConstraints()
:Command("Sketcher_SelectRedundantConstraints")
{
sAppModule = "Sketcher";
sGroup = QT_TR_NOOP("Sketcher");
sMenuText = QT_TR_NOOP("Select Redundant Constraints");
sToolTipText = QT_TR_NOOP("Select Redundant Constraints");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "Sketcher_SelectRedundantConstraints";
sAccel = "CTRL+SHIFT+R";
eType = ForEdit;
}
void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
{
Gui::Document * doc= getActiveGuiDocument();
SketcherGui::ViewProviderSketch* vp = dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
Sketcher::SketchObject* Obj= vp->getSketchObject();
std::string doc_name = Obj->getDocument()->getName();
std::string obj_name = Obj->getNameInDocument();
std::stringstream ss;
// get the needed lists and objects
const std::vector< int > &solverredundant = dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit())->getRedundant();
const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues();
getSelection().clearSelection();
// push the constraints
int i=1;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverredundant.begin();itc != solverredundant.end(); ++itc) {
if ( (*itc) == i){
ss.str(std::string());
ss << "Constraint" << i;
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
break;
}
}
}
}
bool CmdSketcherSelectRedundantConstraints::isActive(void)
{
return isSketcherAcceleratorActive( getActiveGuiDocument(), false );
}
DEF_STD_CMD_A(CmdSketcherSelectConflictingConstraints);
CmdSketcherSelectConflictingConstraints::CmdSketcherSelectConflictingConstraints()
:Command("Sketcher_SelectConflictingConstraints")
{
sAppModule = "Sketcher";
sGroup = QT_TR_NOOP("Sketcher");
sMenuText = QT_TR_NOOP("Select Conflicting Constraints");
sToolTipText = QT_TR_NOOP("Select Conflicting Constraints");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "Sketcher_SelectConflictingConstraints";
sAccel = "CTRL+SHIFT+E";
eType = ForEdit;
}
void CmdSketcherSelectConflictingConstraints::activated(int iMsg)
{
Gui::Document * doc= getActiveGuiDocument();
SketcherGui::ViewProviderSketch* vp = dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
Sketcher::SketchObject* Obj= vp->getSketchObject();
std::string doc_name = Obj->getDocument()->getName();
std::string obj_name = Obj->getNameInDocument();
std::stringstream ss;
// get the needed lists and objects
const std::vector< int > &solverconflicting = dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit())->getConflicting();
const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues();
getSelection().clearSelection();
// push the constraints
int i=1;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverconflicting.begin();itc != solverconflicting.end(); ++itc) {
if ( (*itc) == i){
ss.str(std::string());
ss << "Constraint" << i;
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
break;
}
}
}
}
bool CmdSketcherSelectConflictingConstraints::isActive(void)
{
return isSketcherAcceleratorActive( getActiveGuiDocument(), false );
}
DEF_STD_CMD_A(CmdSketcherSelectElementsAssociatedWithConstraints); DEF_STD_CMD_A(CmdSketcherSelectElementsAssociatedWithConstraints);
CmdSketcherSelectElementsAssociatedWithConstraints::CmdSketcherSelectElementsAssociatedWithConstraints() CmdSketcherSelectElementsAssociatedWithConstraints::CmdSketcherSelectElementsAssociatedWithConstraints()
@ -573,7 +681,6 @@ bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void)
return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
} }
// Add Accelerator Commands
void CreateSketcherCommandsConstraintAccel(void) void CreateSketcherCommandsConstraintAccel(void)
{ {
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
@ -584,5 +691,7 @@ void CreateSketcherCommandsConstraintAccel(void)
rcCmdMgr.addCommand(new CmdSketcherSelectOrigin()); rcCmdMgr.addCommand(new CmdSketcherSelectOrigin());
rcCmdMgr.addCommand(new CmdSketcherSelectVerticalAxis()); rcCmdMgr.addCommand(new CmdSketcherSelectVerticalAxis());
rcCmdMgr.addCommand(new CmdSketcherSelectHorizontalAxis()); rcCmdMgr.addCommand(new CmdSketcherSelectHorizontalAxis());
rcCmdMgr.addCommand(new CmdSketcherSelectRedundantConstraints());
rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints());
rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints());
} }

View File

@ -34,6 +34,7 @@
#include <Gui/ViewProvider.h> #include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h> #include <Gui/WaitCursor.h>
#include <Gui/Selection.h> #include <Gui/Selection.h>
#include <Gui/Command.h>
#include <boost/bind.hpp> #include <boost/bind.hpp>
@ -56,6 +57,13 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView)
connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1)); connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1));
connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1)); connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1));
ui->labelConstrainStatus->setOpenExternalLinks(false);
QObject::connect(
ui->labelConstrainStatus, SIGNAL(linkActivated(const QString &)),
this , SLOT (on_labelConstrainStatus_linkActivated(const QString &))
);
} }
TaskSketcherMessages::~TaskSketcherMessages() TaskSketcherMessages::~TaskSketcherMessages()
@ -75,4 +83,14 @@ void TaskSketcherMessages::slotSolved(QString msg)
ui->labelSolverStatus->setText(msg); ui->labelSolverStatus->setText(msg);
} }
void TaskSketcherMessages::on_labelConstrainStatus_linkActivated(const QString &str)
{
if( str == QString::fromLatin1("#conflicting"))
Gui::Application::Instance->commandManager().runCommandByName("Sketcher_SelectConflictingConstraints");
if( str == QString::fromLatin1("#redundant"))
Gui::Application::Instance->commandManager().runCommandByName("Sketcher_SelectRedundantConstraints");
}
#include "moc_TaskSketcherMessages.cpp" #include "moc_TaskSketcherMessages.cpp"

View File

@ -51,6 +51,7 @@ public:
void slotSolved(QString msg); void slotSolved(QString msg);
private Q_SLOTS: private Q_SLOTS:
void on_labelConstrainStatus_linkActivated(const QString &);
protected: protected:
ViewProviderSketch *sketchView; ViewProviderSketch *sketchView;

View File

@ -3712,11 +3712,22 @@ QString ViewProviderSketch::appendRedundantMsg(const std::vector<int> &redundant
ss << redundant[0]; ss << redundant[0];
for (unsigned int i=1; i < redundant.size(); i++) for (unsigned int i=1; i < redundant.size(); i++)
ss << ", " << redundant[i]; ss << ", " << redundant[i];
ss << "\n"; ss << "\n";
} }
return msg; return msg;
} }
const std::vector<int> &ViewProviderSketch::getConflicting(void) const
{
return edit->ActSketch.getConflicting();
}
const std::vector<int> &ViewProviderSketch::getRedundant(void) const
{
return edit->ActSketch.getRedundant();
}
void ViewProviderSketch::solveSketch(void) void ViewProviderSketch::solveSketch(void)
{ {
// set up the sketch and diagnose possible conflicts // set up the sketch and diagnose possible conflicts
@ -3730,36 +3741,41 @@ void ViewProviderSketch::solveSketch(void)
else if (dofs < 0) { // over-constrained sketch else if (dofs < 0) { // over-constrained sketch
std::string msg; std::string msg;
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
signalSetUp(QString::fromLatin1("<font color='red'>%1<br/>%2</font>") signalSetUp(QString::fromLatin1("<font color='red'>%1<a href=\"#conflicting\"><span style=\" text-decoration: underline; color:#0000ff;\">%2</span></a><br/>%3</font><br/>")
.arg(tr("Over-constrained sketch")) .arg(tr("Over-constrained sketch "))
.arg(tr("(click to select)"))
.arg(QString::fromStdString(msg))); .arg(QString::fromStdString(msg)));
signalSolved(QString()); signalSolved(QString());
} }
else if (edit->ActSketch.hasConflicts()) { // conflicting constraints else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
signalSetUp(QString::fromLatin1("<font color='red'>%1<br/>%2</font>") signalSetUp(QString::fromLatin1("<font color='red'>%1<a href=\"#conflicting\"><span style=\" text-decoration: underline; color:#0000ff;\">%2</span></a><br/>%3</font><br/>")
.arg(tr("Sketch contains conflicting constraints")) .arg(tr("Sketch contains conflicting constraints "))
.arg(tr("(click to select)"))
.arg(appendConflictMsg(edit->ActSketch.getConflicting()))); .arg(appendConflictMsg(edit->ActSketch.getConflicting())));
signalSolved(QString()); signalSolved(QString());
} }
else { else {
if (edit->ActSketch.hasRedundancies()) { // redundant constraints if (edit->ActSketch.hasRedundancies()) { // redundant constraints
signalSetUp(QString::fromLatin1("<font color='orange'>%1<br/>%2</font>") signalSetUp(QString::fromLatin1("<font color='DarkOrange'>%1<a href=\"#redundant\"><span style=\" text-decoration: underline; color:#0000ff;\">%2</span></a><br/>%3</font><br/>")
.arg(tr("Sketch contains redundant constraints")) .arg(tr("Sketch contains redundant constraints "))
.arg(tr("(click to select)"))
.arg(appendRedundantMsg(edit->ActSketch.getRedundant()))); .arg(appendRedundantMsg(edit->ActSketch.getRedundant())));
} }
if (edit->ActSketch.solve() == 0) { // solving the sketch if (edit->ActSketch.solve() == 0) { // solving the sketch
if (dofs == 0) { if (dofs == 0) {
// color the sketch as fully constrained // color the sketch as fully constrained
edit->FullyConstrained = true; edit->FullyConstrained = true;
if (!edit->ActSketch.hasRedundancies()) if (!edit->ActSketch.hasRedundancies()) {
signalSetUp(QString::fromLatin1("<font color='green'>%1</font>").arg(tr("Fully constrained sketch"))); signalSetUp(QString::fromLatin1("<font color='green'>%1</font>").arg(tr("Fully constrained sketch")));
} }
}
else if (!edit->ActSketch.hasRedundancies()) { else if (!edit->ActSketch.hasRedundancies()) {
if (dofs == 1) if (dofs == 1)
signalSetUp(tr("Under-constrained sketch with 1 degree of freedom")); signalSetUp(tr("Under-constrained sketch with 1 degree of freedom"));
else else
signalSetUp(tr("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); signalSetUp(tr("Under-constrained sketch with %1 degrees of freedom").arg(dofs));
} }
signalSolved(tr("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); signalSolved(tr("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
} }
else { else {

View File

@ -220,6 +220,11 @@ public:
/// signals if the elements list has changed /// signals if the elements list has changed
boost::signal<void ()> signalElementsChanged; boost::signal<void ()> signalElementsChanged;
/** @name Act sketch interface */
//@{
const std::vector<int> &getConflicting(void) const;
const std::vector<int> &getRedundant(void) const;
//@}
protected: protected:
virtual bool setEdit(int ModNum); virtual bool setEdit(int ModNum);

View File

@ -210,14 +210,15 @@ inline void SketcherAddWorkbenchTools<Gui::MenuItem>(Gui::MenuItem& consaccel){
<< "Sketcher_SelectOrigin" << "Sketcher_SelectOrigin"
<< "Sketcher_SelectVerticalAxis" << "Sketcher_SelectVerticalAxis"
<< "Sketcher_SelectHorizontalAxis" << "Sketcher_SelectHorizontalAxis"
<< "Sketcher_SelectRedundantConstraints"
<< "Sketcher_SelectConflictingConstraints"
<< "Sketcher_SelectElementsAssociatedWithConstraints"; << "Sketcher_SelectElementsAssociatedWithConstraints";
} }
template <> template <>
inline void SketcherAddWorkbenchTools<Gui::ToolBarItem>(Gui::ToolBarItem& consaccel){ inline void SketcherAddWorkbenchTools<Gui::ToolBarItem>(Gui::ToolBarItem& consaccel){
consaccel << "Sketcher_CloseShape" consaccel << "Sketcher_CloseShape"
<< "Sketcher_ConnectLines" << "Sketcher_ConnectLines"
<< "Sketcher_SelectConstraints" << "Sketcher_SelectConstraints";
<< "Sketcher_SelectElementsAssociatedWithConstraints";
} }
template <typename T> template <typename T>