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;
int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(),
getExternalGeometryCount());
if (dofs < 0) { // over-constrained sketch

View File

@ -448,6 +448,114 @@ bool CmdSketcherSelectHorizontalAxis::isActive(void)
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);
CmdSketcherSelectElementsAssociatedWithConstraints::CmdSketcherSelectElementsAssociatedWithConstraints()
@ -573,7 +681,6 @@ bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void)
return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
}
// Add Accelerator Commands
void CreateSketcherCommandsConstraintAccel(void)
{
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
@ -584,5 +691,7 @@ void CreateSketcherCommandsConstraintAccel(void)
rcCmdMgr.addCommand(new CmdSketcherSelectOrigin());
rcCmdMgr.addCommand(new CmdSketcherSelectVerticalAxis());
rcCmdMgr.addCommand(new CmdSketcherSelectHorizontalAxis());
rcCmdMgr.addCommand(new CmdSketcherSelectRedundantConstraints());
rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints());
rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints());
}

View File

@ -34,6 +34,7 @@
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Gui/Selection.h>
#include <Gui/Command.h>
#include <boost/bind.hpp>
@ -56,6 +57,13 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView)
connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, 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()
@ -75,4 +83,14 @@ void TaskSketcherMessages::slotSolved(QString 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"

View File

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

View File

@ -3688,8 +3688,8 @@ QString ViewProviderSketch::appendConflictMsg(const std::vector<int> &conflictin
if (conflicting.size() > 0) {
if (conflicting.size() == 1)
ss << tr("Please remove the following constraint:");
else
ss << tr("Please remove at least one of the following constraints:");
else
ss << tr("Please remove at least one of the following constraints:");
ss << "\n";
ss << conflicting[0];
for (unsigned int i=1; i < conflicting.size(); i++)
@ -3712,11 +3712,22 @@ QString ViewProviderSketch::appendRedundantMsg(const std::vector<int> &redundant
ss << redundant[0];
for (unsigned int i=1; i < redundant.size(); i++)
ss << ", " << redundant[i];
ss << "\n";
}
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)
{
// set up the sketch and diagnose possible conflicts
@ -3730,29 +3741,33 @@ void ViewProviderSketch::solveSketch(void)
else if (dofs < 0) { // over-constrained sketch
std::string msg;
SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
signalSetUp(QString::fromLatin1("<font color='red'>%1<br/>%2</font>")
.arg(tr("Over-constrained sketch"))
.arg(QString::fromStdString(msg)));
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("(click to select)"))
.arg(QString::fromStdString(msg)));
signalSolved(QString());
}
else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
signalSetUp(QString::fromLatin1("<font color='red'>%1<br/>%2</font>")
.arg(tr("Sketch contains conflicting constraints"))
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("(click to select)"))
.arg(appendConflictMsg(edit->ActSketch.getConflicting())));
signalSolved(QString());
}
else {
if (edit->ActSketch.hasRedundancies()) { // redundant constraints
signalSetUp(QString::fromLatin1("<font color='orange'>%1<br/>%2</font>")
.arg(tr("Sketch contains redundant constraints"))
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("(click to select)"))
.arg(appendRedundantMsg(edit->ActSketch.getRedundant())));
}
if (edit->ActSketch.solve() == 0) { // solving the sketch
if (dofs == 0) {
// color the sketch as fully constrained
edit->FullyConstrained = true;
if (!edit->ActSketch.hasRedundancies())
if (!edit->ActSketch.hasRedundancies()) {
signalSetUp(QString::fromLatin1("<font color='green'>%1</font>").arg(tr("Fully constrained sketch")));
}
}
else if (!edit->ActSketch.hasRedundancies()) {
if (dofs == 1)
@ -3760,6 +3775,7 @@ void ViewProviderSketch::solveSketch(void)
else
signalSetUp(tr("Under-constrained sketch with %1 degrees of freedom").arg(dofs));
}
signalSolved(tr("Solved in %1 sec").arg(edit->ActSketch.SolveTime));
}
else {

View File

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

View File

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