00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
00069
00070 DlgBooleanOperation::~DlgBooleanOperation()
00071 {
00072
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 {
00146 delete child; child = 0;
00147 delete copy; copy = 0;
00148 }
00149
00150
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 {
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
00267
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
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
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"