From 34cc7c31366abc5afc6e4e72c2399b2465ef03ee Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 29 Aug 2014 17:01:10 +0200 Subject: [PATCH] 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). --- src/Mod/Sketcher/App/SketchObject.cpp | 1 + src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 111 +++++++++++++++++- src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp | 18 +++ src/Mod/Sketcher/Gui/TaskSketcherMessages.h | 1 + src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 36 ++++-- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 7 +- src/Mod/Sketcher/Gui/Workbench.cpp | 5 +- 7 files changed, 165 insertions(+), 14 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 595ce664da..3c16a14501 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -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 diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 87ef067898..e3ab6b9c66 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -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(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(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(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(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()); } diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index dc006117a7..0bb72cd375 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -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" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h index cdf5f907bd..198fddf543 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h @@ -51,6 +51,7 @@ public: void slotSolved(QString msg); private Q_SLOTS: + void on_labelConstrainStatus_linkActivated(const QString &); protected: ViewProviderSketch *sketchView; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index dfa774ec7f..f8deb2c11e 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -3688,8 +3688,8 @@ QString ViewProviderSketch::appendConflictMsg(const std::vector &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 &redundant ss << redundant[0]; for (unsigned int i=1; i < redundant.size(); i++) ss << ", " << redundant[i]; + ss << "\n"; } return msg; } +const std::vector &ViewProviderSketch::getConflicting(void) const +{ + return edit->ActSketch.getConflicting(); +} + +const std::vector &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("%1
%2
") - .arg(tr("Over-constrained sketch")) - .arg(QString::fromStdString(msg))); + signalSetUp(QString::fromLatin1("%1%2
%3

") + .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("%1
%2
") - .arg(tr("Sketch contains conflicting constraints")) + signalSetUp(QString::fromLatin1("%1%2
%3

") + .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("%1
%2
") - .arg(tr("Sketch contains redundant constraints")) + signalSetUp(QString::fromLatin1("%1%2
%3

") + .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("%1").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 { diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index b7aa811e53..46969b44ff 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -220,7 +220,12 @@ public: /// signals if the elements list has changed boost::signal signalElementsChanged; - + /** @name Act sketch interface */ + //@{ + const std::vector &getConflicting(void) const; + const std::vector &getRedundant(void) const; + //@} + protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 5aca75008d..2ee7648268 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -210,14 +210,15 @@ inline void SketcherAddWorkbenchTools(Gui::MenuItem& consaccel){ << "Sketcher_SelectOrigin" << "Sketcher_SelectVerticalAxis" << "Sketcher_SelectHorizontalAxis" + << "Sketcher_SelectRedundantConstraints" + << "Sketcher_SelectConflictingConstraints" << "Sketcher_SelectElementsAssociatedWithConstraints"; } template <> inline void SketcherAddWorkbenchTools(Gui::ToolBarItem& consaccel){ consaccel << "Sketcher_CloseShape" << "Sketcher_ConnectLines" - << "Sketcher_SelectConstraints" - << "Sketcher_SelectElementsAssociatedWithConstraints"; + << "Sketcher_SelectConstraints"; } template