DlgBooleanOperation.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2007 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 #ifndef _PreComp_
00026 # include <QMessageBox>
00027 # include <QTreeWidget>
00028 # include <TopoDS_Shape.hxx>
00029 # include <TopExp_Explorer.hxx>
00030 # include <boost/bind.hpp>
00031 #endif
00032 
00033 #include "DlgBooleanOperation.h"
00034 #include "ui_DlgBooleanOperation.h"
00035 #include "../App/PartFeature.h"
00036 #include <Base/Exception.h>
00037 #include <App/Application.h>
00038 #include <App/Document.h>
00039 #include <App/DocumentObject.h>
00040 #include <Gui/Application.h>
00041 #include <Gui/BitmapFactory.h>
00042 #include <Gui/Command.h>
00043 #include <Gui/Document.h>
00044 #include <Gui/Selection.h>
00045 #include <Gui/ViewProvider.h>
00046 #include <Gui/WaitCursor.h>
00047 
00048 using namespace PartGui;
00049 
00050 /* TRANSLATOR PartGui::DlgBooleanOperation */
00051 
00052 DlgBooleanOperation::DlgBooleanOperation(QWidget* parent)
00053   : QWidget(parent), ui(new Ui_DlgBooleanOperation)
00054 {
00055     ui->setupUi(this);
00056     connect(ui->firstShape, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
00057             this, SLOT(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
00058     connect(ui->secondShape, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
00059             this, SLOT(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
00060     this->connectNewObject = App::GetApplication().signalNewObject.connect(boost::bind
00061         (&DlgBooleanOperation::slotCreatedObject, this, _1));
00062     this->connectModObject = App::GetApplication().signalChangedObject.connect(boost::bind
00063         (&DlgBooleanOperation::slotChangedObject, this, _1, _2));
00064     findShapes();
00065 }
00066 
00067 /*  
00068  *  Destroys the object and frees any allocated resources
00069  */
00070 DlgBooleanOperation::~DlgBooleanOperation()
00071 {
00072     // no need to delete child widgets, Qt does it all for us
00073     delete ui;
00074     this->connectNewObject.disconnect();
00075     this->connectModObject.disconnect();
00076 }
00077 
00078 void DlgBooleanOperation::changeEvent(QEvent *e)
00079 {
00080     if (e->type() == QEvent::LanguageChange) {
00081         ui->retranslateUi(this);
00082     }
00083     QWidget::changeEvent(e);
00084 }
00085 
00086 void DlgBooleanOperation::slotCreatedObject(const App::DocumentObject& obj)
00087 {
00088     App::Document* activeDoc = App::GetApplication().getActiveDocument();
00089     if (!activeDoc) return;
00090     App::Document* doc = obj.getDocument();
00091     if (activeDoc == doc && obj.getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
00092         observe.push_back(&obj);
00093     }
00094 }
00095 
00096 void DlgBooleanOperation::slotChangedObject(const App::DocumentObject& obj,
00097                                             const App::Property& prop)
00098 {
00099     std::list<const App::DocumentObject*>::iterator it;
00100     it = std::find(observe.begin(), observe.end(), &obj);
00101     if (it != observe.end() && prop.getTypeId() == Part::PropertyPartShape::getClassTypeId()) {
00102         const TopoDS_Shape& shape = static_cast<const Part::PropertyPartShape&>(prop).getValue();
00103         if (!shape.IsNull()) {
00104             Gui::Document* activeGui = Gui::Application::Instance->getDocument(obj.getDocument());
00105             QString label = QString::fromUtf8(obj.Label.getValue());
00106             QString name = QString::fromAscii(obj.getNameInDocument());
00107             
00108             QTreeWidgetItem* child = new QTreeWidgetItem();
00109             child->setCheckState(0, Qt::Unchecked);
00110             child->setText(0, label);
00111             child->setToolTip(0, label);
00112             child->setData(0, Qt::UserRole, name);
00113             Gui::ViewProvider* vp = activeGui->getViewProvider(&obj);
00114             if (vp)
00115                 child->setIcon(0, vp->getIcon());
00116 
00117             QTreeWidgetItem* copy = child->clone();
00118             copy->setCheckState(0, Qt::Unchecked);
00119 
00120             TopAbs_ShapeEnum type = shape.ShapeType();
00121             if (type == TopAbs_SOLID) {
00122                 ui->firstShape->topLevelItem(0)->addChild(child);
00123                 ui->secondShape->topLevelItem(0)->addChild(copy);
00124                 ui->firstShape->topLevelItem(0)->setExpanded(true);
00125                 ui->secondShape->topLevelItem(0)->setExpanded(true);
00126             }
00127             else if (type == TopAbs_SHELL) {
00128                 ui->firstShape->topLevelItem(1)->addChild(child);
00129                 ui->secondShape->topLevelItem(1)->addChild(copy);
00130                 ui->firstShape->topLevelItem(1)->setExpanded(true);
00131                 ui->secondShape->topLevelItem(1)->setExpanded(true);
00132             }
00133             else if (type == TopAbs_COMPOUND || type == TopAbs_COMPSOLID) {
00134                 ui->firstShape->topLevelItem(2)->addChild(child);
00135                 ui->secondShape->topLevelItem(2)->addChild(copy);
00136                 ui->firstShape->topLevelItem(2)->setExpanded(true);
00137                 ui->secondShape->topLevelItem(2)->setExpanded(true);
00138             }
00139             else if (type == TopAbs_FACE) {
00140                 ui->firstShape->topLevelItem(3)->addChild(child);
00141                 ui->secondShape->topLevelItem(3)->addChild(copy);
00142                 ui->firstShape->topLevelItem(3)->setExpanded(true);
00143                 ui->secondShape->topLevelItem(3)->setExpanded(true);
00144             }
00145             else { // belongs to none of these groups
00146                 delete child; child = 0;
00147                 delete copy; copy = 0;
00148             }
00149 
00150             // remove the watched object because now it is added to the tree
00151             observe.erase(it);
00152         }
00153     }
00154 }
00155 
00156 bool DlgBooleanOperation::hasSolids(const App::DocumentObject* obj) const
00157 {
00158     if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
00159         const TopoDS_Shape& shape = static_cast<const Part::Feature*>(obj)->Shape.getValue();
00160         TopExp_Explorer anExp (shape, TopAbs_SOLID);
00161         for (; anExp.More(); anExp.Next()) {
00162             return true;
00163         }
00164     }
00165 
00166     return false;
00167 }
00168 
00169 void DlgBooleanOperation::findShapes()
00170 {
00171     App::Document* activeDoc = App::GetApplication().getActiveDocument();
00172     if (!activeDoc) return;
00173     Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc);
00174     if (!activeGui) return;
00175 
00176     std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType
00177         (Part::Feature::getClassTypeId());
00178 
00179     QTreeWidgetItem *item_left=0, *item_right=0;
00180     for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it!=objs.end(); ++it) {
00181         const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
00182         if (!shape.IsNull()) {
00183             QString label = QString::fromUtf8((*it)->Label.getValue());
00184             QString name = QString::fromAscii((*it)->getNameInDocument());
00185             
00186             QTreeWidgetItem* child = new QTreeWidgetItem();
00187             child->setCheckState(0, Qt::Unchecked);
00188             child->setText(0, label);
00189             child->setToolTip(0, label);
00190             child->setData(0, Qt::UserRole, name);
00191             Gui::ViewProvider* vp = activeGui->getViewProvider(*it);
00192             if (vp)
00193                 child->setIcon(0, vp->getIcon());
00194 
00195             QTreeWidgetItem* copy = child->clone();
00196             copy->setCheckState(0, Qt::Unchecked);
00197 
00198             TopAbs_ShapeEnum type = shape.ShapeType();
00199             if (type == TopAbs_SOLID) {
00200                 ui->firstShape->topLevelItem(0)->addChild(child);
00201                 ui->secondShape->topLevelItem(0)->addChild(copy);
00202             }
00203             else if (type == TopAbs_SHELL) {
00204                 ui->firstShape->topLevelItem(1)->addChild(child);
00205                 ui->secondShape->topLevelItem(1)->addChild(copy);
00206             }
00207             else if (type == TopAbs_COMPOUND || type == TopAbs_COMPSOLID) {
00208                 ui->firstShape->topLevelItem(2)->addChild(child);
00209                 ui->secondShape->topLevelItem(2)->addChild(copy);
00210             }
00211             else if (type == TopAbs_FACE) {
00212                 ui->firstShape->topLevelItem(3)->addChild(child);
00213                 ui->secondShape->topLevelItem(3)->addChild(copy);
00214             }
00215             else { // belongs to none of these groups
00216                 delete child; child = 0;
00217                 delete copy; copy = 0;
00218             }
00219 
00220             if (!item_left || !item_right) {
00221                 bool selected = Gui::Selection().isSelected(*it);
00222                 if (!item_left && selected)
00223                     item_left = child;
00224                 else if (!item_right && selected)
00225                     item_right = copy;
00226             }
00227         }
00228     }
00229 
00230     if (item_left) {
00231         item_left->setCheckState(0, Qt::Checked);
00232         ui->firstShape->setCurrentItem(item_left);
00233     }
00234     if (item_right) {
00235         item_right->setCheckState(0, Qt::Checked);
00236         ui->secondShape->setCurrentItem(item_right);
00237     }
00238     for (int i = 0; i < ui->firstShape->topLevelItemCount(); i++) {
00239         QTreeWidgetItem* group = ui->firstShape->topLevelItem(i);
00240         group->setFlags(Qt::ItemIsEnabled);
00241         if (group->childCount() > 0)
00242             group->setExpanded(true);
00243     }
00244     for (int i = 0; i < ui->secondShape->topLevelItemCount(); i++) {
00245         QTreeWidgetItem* group = ui->secondShape->topLevelItem(i);
00246         group->setFlags(Qt::ItemIsEnabled);
00247         if (group->childCount() > 0)
00248             group->setExpanded(true);
00249     }
00250 }
00251 
00252 bool DlgBooleanOperation::indexOfCurrentItem(QTreeWidgetItem* item, int& top_ind, int& child_ind) const
00253 {
00254     QTreeWidgetItem* parent = item->parent();
00255     if (parent) {
00256         top_ind = parent->treeWidget()->indexOfTopLevelItem(parent);
00257         child_ind = parent->indexOfChild(item);
00258         return true;
00259     }
00260 
00261     return false;
00262 }
00263 
00264 void DlgBooleanOperation::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem * previous)
00265 {
00266 //    if (current && current->flags() & Qt::ItemIsUserCheckable)
00267 //        current->setCheckState(0, Qt::Checked);
00268     if (previous && previous->flags() & Qt::ItemIsUserCheckable)
00269         previous->setCheckState(0, Qt::Unchecked);
00270 }
00271 
00272 void DlgBooleanOperation::on_swapButton_clicked()
00273 {
00274     QTreeWidgetItem* lChild = ui->firstShape->currentItem();
00275     bool lsel = (lChild && (lChild->checkState(0) & Qt::Checked));
00276     QTreeWidgetItem* rChild = ui->secondShape->currentItem();
00277     bool rsel = (rChild && (rChild->checkState(0) & Qt::Checked));
00278 
00279     if (rsel) {
00280         int top_index, child_ind;
00281         if (indexOfCurrentItem(rChild, top_index, child_ind)) {
00282             QTreeWidgetItem* child = ui->firstShape->topLevelItem(top_index)->child(child_ind);
00283             child->setCheckState(0, Qt::Checked);
00284             ui->firstShape->setCurrentItem(child);
00285         }
00286     }
00287     if (lsel) {
00288         int top_index, child_ind;
00289         if (indexOfCurrentItem(lChild, top_index, child_ind)) {
00290             QTreeWidgetItem* child = ui->secondShape->topLevelItem(top_index)->child(child_ind);
00291             child->setCheckState(0, Qt::Checked);
00292             ui->secondShape->setCurrentItem(child);
00293         }
00294     }
00295 }
00296 
00297 void DlgBooleanOperation::accept()
00298 {
00299     int ltop, lchild, rtop, rchild;
00300     QTreeWidgetItem* litem = ui->firstShape->currentItem();
00301     bool lsel = (litem && (litem->checkState(0) & Qt::Checked));
00302     QTreeWidgetItem* ritem = ui->secondShape->currentItem();
00303     bool rsel = (ritem && (ritem->checkState(0) & Qt::Checked));
00304 
00305     if (!lsel || !indexOfCurrentItem(litem,ltop,lchild)) {
00306         QMessageBox::critical(this, windowTitle(), 
00307             tr("Select a shape on the left side, first"));
00308         return;
00309     }
00310     if (!rsel || !indexOfCurrentItem(ritem,rtop,rchild)) {
00311         QMessageBox::critical(this, windowTitle(), 
00312             tr("Select a shape on the right side, first"));
00313         return;
00314     }
00315     if (ltop == rtop && lchild == rchild) {
00316         QMessageBox::critical(this, windowTitle(), 
00317             tr("Cannot perform a boolean operation with the same shape"));
00318         return;
00319     }
00320 
00321     std::string shapeOne, shapeTwo;
00322     shapeOne = (const char*)litem->data(0, Qt::UserRole).toByteArray();
00323     shapeTwo = (const char*)ritem->data(0, Qt::UserRole).toByteArray();
00324     App::Document* activeDoc = App::GetApplication().getActiveDocument();
00325     if (!activeDoc) {
00326         QMessageBox::critical(this, windowTitle(), 
00327             tr("No active document available"));
00328         return;
00329     }
00330 
00331     std::string type, objName;
00332     App::DocumentObject* obj1 = activeDoc->getObject(shapeOne.c_str());
00333     App::DocumentObject* obj2 = activeDoc->getObject(shapeTwo.c_str());
00334     if (!obj1 || !obj2) {
00335         // objects don't exists (anymore)
00336         QMessageBox::critical(this, windowTitle(), 
00337             tr("One of the selected objects doesn't exist anymore"));
00338         return;
00339     }
00340 
00341     if (ui->unionButton->isChecked()) {
00342         if (!hasSolids(obj1) || !hasSolids(obj2)) {
00343             QMessageBox::critical(this, windowTitle(), 
00344                 tr("Performing union on non-solids is not possible"));
00345             return;
00346         }
00347         type = "Part::Fuse";
00348         objName = activeDoc->getUniqueObjectName("Fusion");
00349     }
00350     else if (ui->interButton->isChecked()) {
00351         if (!hasSolids(obj1) || !hasSolids(obj2)) {
00352             QMessageBox::critical(this, windowTitle(), 
00353                 tr("Performing intersection on non-solids is not possible"));
00354             return;
00355         }
00356         type = "Part::Common";
00357         objName = activeDoc->getUniqueObjectName("Common");
00358     }
00359     else if (ui->diffButton->isChecked()) {
00360         if (!hasSolids(obj1) || !hasSolids(obj2)) {
00361             QMessageBox::critical(this, windowTitle(), 
00362                 tr("Performing difference on non-solids is not possible"));
00363             return;
00364         }
00365         type = "Part::Cut";
00366         objName = activeDoc->getUniqueObjectName("Cut");
00367     }
00368     else if (ui->sectionButton->isChecked()) {
00369         type = "Part::Section";
00370         objName = activeDoc->getUniqueObjectName("Section");
00371     }
00372 
00373     try {
00374         Gui::WaitCursor wc;
00375         activeDoc->openTransaction("Boolean operation");
00376         Gui::Command::doCommand(Gui::Command::Doc,
00377             "App.activeDocument().addObject(\"%s\",\"%s\")",
00378             type.c_str(), objName.c_str());
00379         Gui::Command::doCommand(Gui::Command::Doc,
00380             "App.activeDocument().%s.Base = App.activeDocument().%s",
00381             objName.c_str(),shapeOne.c_str());
00382         Gui::Command::doCommand(Gui::Command::Doc,
00383             "App.activeDocument().%s.Tool = App.activeDocument().%s",
00384             objName.c_str(),shapeTwo.c_str());
00385         Gui::Command::doCommand(Gui::Command::Gui,
00386             "Gui.activeDocument().hide(\"%s\")",shapeOne.c_str());
00387         Gui::Command::doCommand(Gui::Command::Gui,
00388             "Gui.activeDocument().hide(\"%s\")",shapeTwo.c_str());
00389         Gui::Command::doCommand(Gui::Command::Gui,
00390             "Gui.activeDocument().%s.ShapeColor = Gui.activeDocument().%s.ShapeColor",
00391             objName.c_str(),shapeOne.c_str());
00392         activeDoc->commitTransaction();
00393         activeDoc->recompute();
00394     }
00395     catch (const Base::Exception& e) {
00396         e.ReportException();
00397     }
00398 }
00399 
00400 // ---------------------------------------
00401 
00402 TaskBooleanOperation::TaskBooleanOperation()
00403 {
00404     widget = new DlgBooleanOperation();
00405     taskbox = new Gui::TaskView::TaskBox(
00406         Gui::BitmapFactory().pixmap("Part_Booleans"),
00407         widget->windowTitle(), false, 0);
00408     taskbox->groupLayout()->addWidget(widget);
00409     Content.push_back(taskbox);
00410 }
00411 
00412 TaskBooleanOperation::~TaskBooleanOperation()
00413 {
00414     // automatically deleted in the sub-class
00415 }
00416 
00417 void TaskBooleanOperation::clicked(int id)
00418 {
00419     if (id == QDialogButtonBox::Apply) {
00420         widget->accept();
00421     }
00422 }
00423 
00424 #include "moc_DlgBooleanOperation.cpp"

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