TaskShapeBuilder.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <TopExp_Explorer.hxx>
00028 # include <TopTools_IndexedMapOfShape.hxx>
00029 # include <QButtonGroup>
00030 # include <QMessageBox>
00031 # include <QTextStream>
00032 #endif
00033 
00034 #include "ui_TaskShapeBuilder.h"
00035 #include "TaskShapeBuilder.h"
00036 #include "ViewProviderExt.h"
00037 
00038 #include <Gui/Application.h>
00039 #include <Gui/BitmapFactory.h>
00040 #include <Gui/Document.h>
00041 #include <Gui/Selection.h>
00042 #include <Gui/SelectionFilter.h>
00043 
00044 #include <Base/Console.h>
00045 #include <Base/Interpreter.h>
00046 #include <App/Application.h>
00047 #include <App/Document.h>
00048 #include <App/DocumentObject.h>
00049 #include <Mod/Part/App/PartFeature.h>
00050 
00051 
00052 using namespace PartGui;
00053 
00054 namespace PartGui {
00055     class ShapeSelection : public Gui::SelectionFilterGate
00056     {
00057     public:
00058         enum Type {VERTEX, EDGE, FACE, ALL};
00059         Type mode;
00060         ShapeSelection()
00061             : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), mode(ALL)
00062         {
00063         }
00064         void setMode(Type mode)
00065         {
00066             this->mode = mode;
00067         }
00068         bool allow(App::Document*, App::DocumentObject* obj, const char*sSubName)
00069         {
00070             if (!obj || !obj->isDerivedFrom(Part::Feature::getClassTypeId()))
00071                 return false;
00072             if (!sSubName || sSubName[0] == '\0')
00073                 return (mode == ALL);
00074             std::string element(sSubName);
00075             switch (mode) {
00076             case VERTEX:
00077                 return element.substr(0,6) == "Vertex";
00078             case EDGE:
00079                 return element.substr(0,4) == "Edge";
00080             case FACE:
00081                 return element.substr(0,4) == "Face";
00082             default:
00083                 return true;
00084             }
00085         }
00086     };
00087 }
00088 
00089 class ShapeBuilderWidget::Private
00090 {
00091 public:
00092     Ui_TaskShapeBuilder ui;
00093     QButtonGroup bg;
00094     ShapeSelection* gate;
00095     Private()
00096     {
00097     }
00098     ~Private()
00099     {
00100     }
00101 };
00102 
00103 /* TRANSLATOR PartGui::ShapeBuilderWidget */
00104 
00105 ShapeBuilderWidget::ShapeBuilderWidget(QWidget* parent)
00106   : d(new Private())
00107 {
00108     Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
00109     Gui::Application::Instance->runPythonCode("import Part");
00110 
00111     d->ui.setupUi(this);
00112     d->ui.label->setText(QString());
00113     d->bg.addButton(d->ui.radioButtonEdge, 0);
00114     d->bg.addButton(d->ui.radioButtonFace, 1);
00115     d->bg.addButton(d->ui.radioButtonShell, 2);
00116     d->bg.addButton(d->ui.radioButtonSolid, 3);
00117     d->bg.setExclusive(true);
00118 
00119     connect(&d->bg, SIGNAL(buttonClicked(int)),
00120             this, SLOT(switchMode(int)));
00121 
00122     d->gate = new ShapeSelection();
00123     Gui::Selection().addSelectionGate(d->gate);
00124 
00125     d->bg.button(0)->setChecked(true);
00126     switchMode(0);
00127 }
00128 
00129 ShapeBuilderWidget::~ShapeBuilderWidget()
00130 {
00131     Gui::Selection().rmvSelectionGate();
00132     delete d;
00133 }
00134 
00135 void ShapeBuilderWidget::on_createButton_clicked()
00136 {
00137     int mode = d->bg.checkedId();
00138     Gui::Document* doc = Gui::Application::Instance->activeDocument();
00139     if (!doc) return;
00140 
00141     try {
00142         if (mode == 0) {
00143             createEdge();
00144         }
00145         else if (mode == 1) {
00146             createFace();
00147         }
00148         else if (mode == 2) {
00149             createShell();
00150         }
00151         else if (mode == 3) {
00152             createSolid();
00153         }
00154         doc->getDocument()->recompute();
00155     }
00156     catch (const Base::Exception& e) {
00157         Base::Console().Error("%s\n", e.what());
00158     }
00159 }
00160 
00161 void ShapeBuilderWidget::createEdge()
00162 {
00163     Gui::SelectionFilter vertexFilter  ("SELECT Part::Feature SUBELEMENT Vertex COUNT 2");
00164     bool matchVertex = vertexFilter.match();
00165     if (!matchVertex) {
00166         QMessageBox::critical(this, tr("Wrong selection"), tr("Select two vertices"));
00167         return;
00168     }
00169 
00170     std::vector<Gui::SelectionObject> sel = vertexFilter.Result[0];
00171     std::vector<QString> elements;
00172     std::vector<Gui::SelectionObject>::iterator it;
00173     std::vector<std::string>::const_iterator jt;
00174     for (it=sel.begin();it!=sel.end();++it) {
00175         for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00176             QString line;
00177             QTextStream str(&line);
00178             str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ".Point";
00179             elements.push_back(line);
00180         }
00181     }
00182 
00183     // should actually never happen
00184     if (elements.size() != 2) {
00185         QMessageBox::critical(this, tr("Wrong selection"), tr("Select two vertices"));
00186         return;
00187     }
00188 
00189     QString cmd;
00190     cmd = QString::fromAscii(
00191         "_=Part.makeLine(%1, %2)\n"
00192         "if _.isNull(): raise Exception('Failed to create edge')\n"
00193         "App.ActiveDocument.addObject('Part::Feature','Edge').Shape=_\n"
00194         "del _\n"
00195     ).arg(elements[0]).arg(elements[1]);
00196 
00197     Gui::Application::Instance->activeDocument()->openCommand("Edge");
00198     Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00199     Gui::Application::Instance->activeDocument()->commitCommand();
00200 }
00201 
00202 void ShapeBuilderWidget::createFace()
00203 {
00204     Gui::SelectionFilter edgeFilter  ("SELECT Part::Feature SUBELEMENT Edge COUNT 3..");
00205     bool matchEdge = edgeFilter.match();
00206     if (!matchEdge) {
00207         QMessageBox::critical(this, tr("Wrong selection"), tr("Select three or more edges"));
00208         return;
00209     }
00210 
00211     std::vector<Gui::SelectionObject> sel = edgeFilter.Result[0];
00212     std::vector<Gui::SelectionObject>::iterator it;
00213     std::vector<std::string>::const_iterator jt;
00214 
00215     QString list;
00216     QTextStream str(&list);
00217     str << "[";
00218     for (it=sel.begin();it!=sel.end();++it) {
00219         for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00220             str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ", ";
00221         }
00222     }
00223     str << "]";
00224 
00225     QString cmd;
00226     if (d->ui.checkPlanar->isChecked()) {
00227         cmd = QString::fromAscii(
00228             "_=Part.Face(Part.Wire(Part.__sortEdges__(%1)))\n"
00229             "if _.isNull(): raise Exception('Failed to create face')\n"
00230             "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n"
00231             "del _\n"
00232         ).arg(list);
00233     }
00234     else {
00235         cmd = QString::fromAscii(
00236             "_=Part.makeFilledFace(Part.__sortEdges__(%1))\n"
00237             "if _.isNull(): raise Exception('Failed to create face')\n"
00238             "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n"
00239             "del _\n"
00240         ).arg(list);
00241     }
00242 
00243     Gui::Application::Instance->activeDocument()->openCommand("Face");
00244     Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00245     Gui::Application::Instance->activeDocument()->commitCommand();
00246 }
00247 
00248 void ShapeBuilderWidget::createShell()
00249 {
00250     Gui::SelectionFilter faceFilter  ("SELECT Part::Feature SUBELEMENT Face COUNT 2..");
00251     bool matchFace = faceFilter.match();
00252     if (!matchFace) {
00253         QMessageBox::critical(this, tr("Wrong selection"), tr("Select two or more faces"));
00254         return;
00255     }
00256 
00257     std::vector<Gui::SelectionObject> sel = faceFilter.Result[0];
00258     std::vector<Gui::SelectionObject>::iterator it;
00259     std::vector<std::string>::const_iterator jt;
00260 
00261     QString list;
00262     QTextStream str(&list);
00263     if (d->ui.checkFaces->isChecked()) {
00264         std::set<App::DocumentObject*> obj;
00265         for (it=sel.begin();it!=sel.end();++it)
00266             obj.insert(it->getObject());
00267         str << "[]";
00268         for (std::set<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) {
00269             str << "+ App.ActiveDocument." << (*it)->getNameInDocument() << ".Shape.Faces";
00270         }
00271     }
00272     else {
00273         str << "[";
00274         for (it=sel.begin();it!=sel.end();++it) {
00275             for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00276                 str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ", ";
00277             }
00278         }
00279         str << "]";
00280     }
00281 
00282     QString cmd;
00283     cmd = QString::fromAscii(
00284         "_=Part.Shell(%1)\n"
00285         "if _.isNull(): raise Exception('Failed to create shell')\n"
00286         "App.ActiveDocument.addObject('Part::Feature','Shell').Shape=_\n"
00287         "del _\n"
00288     ).arg(list);
00289 
00290     Gui::Application::Instance->activeDocument()->openCommand("Shell");
00291     Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00292     Gui::Application::Instance->activeDocument()->commitCommand();
00293 }
00294 
00295 void ShapeBuilderWidget::createSolid()
00296 {
00297     Gui::SelectionFilter partFilter  ("SELECT Part::Feature COUNT 1");
00298     bool matchPart = partFilter.match();
00299     if (!matchPart) {
00300         QMessageBox::critical(this, tr("Wrong selection"), tr("Select only one part object"));
00301         return;
00302     }
00303 
00304     QString line;
00305     QTextStream str(&line);
00306 
00307     std::vector<Gui::SelectionObject> sel = partFilter.Result[0];
00308     std::vector<Gui::SelectionObject>::iterator it;
00309     for (it=sel.begin();it!=sel.end();++it) {
00310         str << "App.ActiveDocument." << it->getFeatName() << ".Shape";
00311         break;
00312     }
00313 
00314     QString cmd;
00315     cmd = QString::fromAscii(
00316         "shell=%1\n"
00317         "if shell.ShapeType != 'Shell': raise Exception('Part object is not a shell')\n"
00318         "_=Part.Solid(shell)\n"
00319         "if _.isNull(): raise Exception('Failed to create solid')\n"
00320         "App.ActiveDocument.addObject('Part::Feature','Solid').Shape=_\n"
00321         "del _\n"
00322     ).arg(line);
00323 
00324     Gui::Application::Instance->activeDocument()->openCommand("Solid");
00325     Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00326     Gui::Application::Instance->activeDocument()->commitCommand();
00327 }
00328 
00329 void ShapeBuilderWidget::switchMode(int mode)
00330 {
00331     Gui::Selection().clearSelection();
00332     if (mode == 0) {
00333         d->gate->setMode(ShapeSelection::VERTEX);
00334         d->ui.label->setText(tr("Select two vertices to create an edge"));
00335         d->ui.checkPlanar->setEnabled(false);
00336         d->ui.checkFaces->setEnabled(false);
00337     }
00338     else if (mode == 1) {
00339         d->gate->setMode(ShapeSelection::EDGE);
00340         d->ui.label->setText(tr("Select a closed set of edges"));
00341         d->ui.checkPlanar->setEnabled(true);
00342         d->ui.checkFaces->setEnabled(false);
00343     }
00344     else if (mode == 2) {
00345         d->gate->setMode(ShapeSelection::FACE);
00346         d->ui.label->setText(tr("Select adjacent faces"));
00347         d->ui.checkPlanar->setEnabled(false);
00348         d->ui.checkFaces->setEnabled(true);
00349     }
00350     else {
00351         d->gate->setMode(ShapeSelection::ALL);
00352         d->ui.label->setText(tr("All shape types can be selected"));
00353         d->ui.checkPlanar->setEnabled(false);
00354         d->ui.checkFaces->setEnabled(false);
00355     }
00356 }
00357 
00358 bool ShapeBuilderWidget::accept()
00359 {
00360     return true;
00361 }
00362 
00363 bool ShapeBuilderWidget::reject()
00364 {
00365     return true;
00366 }
00367 
00368 void ShapeBuilderWidget::changeEvent(QEvent *e)
00369 {
00370     QWidget::changeEvent(e);
00371     if (e->type() == QEvent::LanguageChange) {
00372         d->ui.retranslateUi(this);
00373     }
00374 }
00375 
00376 
00377 /* TRANSLATOR PartGui::TaskShapeBuilder */
00378 
00379 TaskShapeBuilder::TaskShapeBuilder()
00380 {
00381     widget = new ShapeBuilderWidget();
00382     taskbox = new Gui::TaskView::TaskBox(
00383         Gui::BitmapFactory().pixmap("Part_Shapebuilder"),
00384         widget->windowTitle(), true, 0);
00385     taskbox->groupLayout()->addWidget(widget);
00386     Content.push_back(taskbox);
00387 }
00388 
00389 TaskShapeBuilder::~TaskShapeBuilder()
00390 {
00391 }
00392 
00393 void TaskShapeBuilder::open()
00394 {
00395 }
00396 
00397 void TaskShapeBuilder::clicked(int)
00398 {
00399 }
00400 
00401 bool TaskShapeBuilder::accept()
00402 {
00403     return widget->accept();
00404 }
00405 
00406 bool TaskShapeBuilder::reject()
00407 {
00408     return widget->reject();
00409 }
00410 
00411 #include "moc_TaskShapeBuilder.cpp"

Generated on Wed Nov 23 19:00:44 2011 for FreeCAD by  doxygen 1.6.1