/*************************************************************************** * Copyright (c) 2007 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include #endif #include "DlgBooleanOperation.h" #include "ui_DlgBooleanOperation.h" #include "../App/PartFeature.h" #include #include #include #include #include #include #include #include #include #include #include using namespace PartGui; namespace PartGui { class BooleanOperationItem : public QTreeWidgetItem { public: BooleanOperationItem(int type = Type) : QTreeWidgetItem(type) { } void setData (int column, int role, const QVariant & value) { QTreeWidgetItem::setData(column, role, value); if (role == Qt::CheckStateRole && value.toBool() == true) { QTreeWidget* tree = this->treeWidget(); if (!tree) return; int numChild = tree->topLevelItemCount(); for (int i=0; itopLevelItem(i); for (int j=0; jchildCount(); j++) { QTreeWidgetItem* child = item->child(j); if (child && child->checkState(column) & Qt::Checked) { if (child != this) child->setCheckState(column, Qt::Unchecked); } } } } } }; } /* TRANSLATOR PartGui::DlgBooleanOperation */ DlgBooleanOperation::DlgBooleanOperation(QWidget* parent) : QWidget(parent), ui(new Ui_DlgBooleanOperation) { ui->setupUi(this); connect(ui->firstShape, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); connect(ui->secondShape, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); this->connectNewObject = App::GetApplication().signalNewObject.connect(boost::bind (&DlgBooleanOperation::slotCreatedObject, this, _1)); this->connectModObject = App::GetApplication().signalChangedObject.connect(boost::bind (&DlgBooleanOperation::slotChangedObject, this, _1, _2)); findShapes(); } /* * Destroys the object and frees any allocated resources */ DlgBooleanOperation::~DlgBooleanOperation() { // no need to delete child widgets, Qt does it all for us delete ui; this->connectNewObject.disconnect(); this->connectModObject.disconnect(); } void DlgBooleanOperation::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } QWidget::changeEvent(e); } void DlgBooleanOperation::slotCreatedObject(const App::DocumentObject& obj) { App::Document* activeDoc = App::GetApplication().getActiveDocument(); if (!activeDoc) return; App::Document* doc = obj.getDocument(); if (activeDoc == doc && obj.getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { observe.push_back(&obj); } } void DlgBooleanOperation::slotChangedObject(const App::DocumentObject& obj, const App::Property& prop) { std::list::iterator it; it = std::find(observe.begin(), observe.end(), &obj); if (it != observe.end() && prop.getTypeId() == Part::PropertyPartShape::getClassTypeId()) { const TopoDS_Shape& shape = static_cast(prop).getValue(); if (!shape.IsNull()) { Gui::Document* activeGui = Gui::Application::Instance->getDocument(obj.getDocument()); QString label = QString::fromUtf8(obj.Label.getValue()); QString name = QString::fromAscii(obj.getNameInDocument()); QTreeWidgetItem* child = new BooleanOperationItem(); child->setCheckState(0, Qt::Unchecked); child->setText(0, label); child->setToolTip(0, label); child->setData(0, Qt::UserRole, name); Gui::ViewProvider* vp = activeGui->getViewProvider(&obj); if (vp) child->setIcon(0, vp->getIcon()); QTreeWidgetItem* copy = new BooleanOperationItem(); copy->setCheckState(0, Qt::Unchecked); copy->setText(0, label); copy->setToolTip(0, label); copy->setData(0, Qt::UserRole, name); if (vp) copy->setIcon(0, vp->getIcon()); TopAbs_ShapeEnum type = shape.ShapeType(); if (type == TopAbs_SOLID) { ui->firstShape->topLevelItem(0)->addChild(child); ui->secondShape->topLevelItem(0)->addChild(copy); ui->firstShape->topLevelItem(0)->setExpanded(true); ui->secondShape->topLevelItem(0)->setExpanded(true); } else if (type == TopAbs_SHELL) { ui->firstShape->topLevelItem(1)->addChild(child); ui->secondShape->topLevelItem(1)->addChild(copy); ui->firstShape->topLevelItem(1)->setExpanded(true); ui->secondShape->topLevelItem(1)->setExpanded(true); } else if (type == TopAbs_COMPOUND || type == TopAbs_COMPSOLID) { ui->firstShape->topLevelItem(2)->addChild(child); ui->secondShape->topLevelItem(2)->addChild(copy); ui->firstShape->topLevelItem(2)->setExpanded(true); ui->secondShape->topLevelItem(2)->setExpanded(true); } else if (type == TopAbs_FACE) { ui->firstShape->topLevelItem(3)->addChild(child); ui->secondShape->topLevelItem(3)->addChild(copy); ui->firstShape->topLevelItem(3)->setExpanded(true); ui->secondShape->topLevelItem(3)->setExpanded(true); } else { // belongs to none of these groups delete child; child = 0; delete copy; copy = 0; } // remove the watched object because now it is added to the tree observe.erase(it); } } } bool DlgBooleanOperation::hasSolids(const App::DocumentObject* obj) const { if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { const TopoDS_Shape& shape = static_cast(obj)->Shape.getValue(); TopExp_Explorer anExp (shape, TopAbs_SOLID); for (; anExp.More(); anExp.Next()) { return true; } } return false; } void DlgBooleanOperation::findShapes() { App::Document* activeDoc = App::GetApplication().getActiveDocument(); if (!activeDoc) return; Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); if (!activeGui) return; std::vector objs = activeDoc->getObjectsOfType (Part::Feature::getClassTypeId()); QTreeWidgetItem *item_left=0, *item_right=0; for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); if (!shape.IsNull()) { QString label = QString::fromUtf8((*it)->Label.getValue()); QString name = QString::fromAscii((*it)->getNameInDocument()); QTreeWidgetItem* child = new BooleanOperationItem(); child->setCheckState(0, Qt::Unchecked); child->setText(0, label); child->setToolTip(0, label); child->setData(0, Qt::UserRole, name); Gui::ViewProvider* vp = activeGui->getViewProvider(*it); if (vp) child->setIcon(0, vp->getIcon()); QTreeWidgetItem* copy = new BooleanOperationItem(); copy->setCheckState(0, Qt::Unchecked); copy->setText(0, label); copy->setToolTip(0, label); copy->setData(0, Qt::UserRole, name); if (vp) copy->setIcon(0, vp->getIcon()); TopAbs_ShapeEnum type = shape.ShapeType(); if (type == TopAbs_SOLID) { ui->firstShape->topLevelItem(0)->addChild(child); ui->secondShape->topLevelItem(0)->addChild(copy); } else if (type == TopAbs_SHELL) { ui->firstShape->topLevelItem(1)->addChild(child); ui->secondShape->topLevelItem(1)->addChild(copy); } else if (type == TopAbs_COMPOUND || type == TopAbs_COMPSOLID) { ui->firstShape->topLevelItem(2)->addChild(child); ui->secondShape->topLevelItem(2)->addChild(copy); } else if (type == TopAbs_FACE) { ui->firstShape->topLevelItem(3)->addChild(child); ui->secondShape->topLevelItem(3)->addChild(copy); } else { // belongs to none of these groups delete child; child = 0; delete copy; copy = 0; } if (!item_left || !item_right) { bool selected = Gui::Selection().isSelected(*it); if (!item_left && selected) item_left = child; else if (!item_right && selected) item_right = copy; } } } if (item_left) { item_left->setCheckState(0, Qt::Checked); ui->firstShape->setCurrentItem(item_left); } if (item_right) { item_right->setCheckState(0, Qt::Checked); ui->secondShape->setCurrentItem(item_right); } for (int i = 0; i < ui->firstShape->topLevelItemCount(); i++) { QTreeWidgetItem* group = ui->firstShape->topLevelItem(i); group->setFlags(Qt::ItemIsEnabled); if (group->childCount() > 0) group->setExpanded(true); } for (int i = 0; i < ui->secondShape->topLevelItemCount(); i++) { QTreeWidgetItem* group = ui->secondShape->topLevelItem(i); group->setFlags(Qt::ItemIsEnabled); if (group->childCount() > 0) group->setExpanded(true); } } bool DlgBooleanOperation::indexOfCurrentItem(QTreeWidgetItem* item, int& top_ind, int& child_ind) const { QTreeWidgetItem* parent = item->parent(); if (parent) { top_ind = parent->treeWidget()->indexOfTopLevelItem(parent); child_ind = parent->indexOfChild(item); return true; } return false; } void DlgBooleanOperation::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem * previous) { // if (current && current->flags() & Qt::ItemIsUserCheckable) // current->setCheckState(0, Qt::Checked); //if (previous && previous->flags() & Qt::ItemIsUserCheckable) // previous->setCheckState(0, Qt::Unchecked); } void DlgBooleanOperation::on_swapButton_clicked() { QTreeWidgetItem* lChild = ui->firstShape->currentItem(); bool lsel = (lChild && (lChild->checkState(0) & Qt::Checked)); QTreeWidgetItem* rChild = ui->secondShape->currentItem(); bool rsel = (rChild && (rChild->checkState(0) & Qt::Checked)); if (rsel) { int top_index, child_ind; if (indexOfCurrentItem(rChild, top_index, child_ind)) { QTreeWidgetItem* child = ui->firstShape->topLevelItem(top_index)->child(child_ind); child->setCheckState(0, Qt::Checked); ui->firstShape->setCurrentItem(child); } } if (lsel) { int top_index, child_ind; if (indexOfCurrentItem(lChild, top_index, child_ind)) { QTreeWidgetItem* child = ui->secondShape->topLevelItem(top_index)->child(child_ind); child->setCheckState(0, Qt::Checked); ui->secondShape->setCurrentItem(child); } } } void DlgBooleanOperation::accept() { int ltop, lchild, rtop, rchild; QTreeWidgetItem* litem = 0; int numLChild = ui->firstShape->topLevelItemCount(); for (int i=0; ifirstShape->topLevelItem(i); for (int j=0; jchildCount(); j++) { QTreeWidgetItem* child = item->child(j); if (child && child->checkState(0) & Qt::Checked) { litem = child; break; } } if (litem) break; } QTreeWidgetItem* ritem = 0; int numRChild = ui->secondShape->topLevelItemCount(); for (int i=0; isecondShape->topLevelItem(i); for (int j=0; jchildCount(); j++) { QTreeWidgetItem* child = item->child(j); if (child && child->checkState(0) & Qt::Checked) { ritem = child; break; } } if (ritem) break; } if (!litem || !indexOfCurrentItem(litem,ltop,lchild)) { QMessageBox::critical(this, windowTitle(), tr("Select a shape on the left side, first")); return; } if (!ritem || !indexOfCurrentItem(ritem,rtop,rchild)) { QMessageBox::critical(this, windowTitle(), tr("Select a shape on the right side, first")); return; } if (ltop == rtop && lchild == rchild) { QMessageBox::critical(this, windowTitle(), tr("Cannot perform a boolean operation with the same shape")); return; } std::string shapeOne, shapeTwo; shapeOne = (const char*)litem->data(0, Qt::UserRole).toByteArray(); shapeTwo = (const char*)ritem->data(0, Qt::UserRole).toByteArray(); App::Document* activeDoc = App::GetApplication().getActiveDocument(); if (!activeDoc) { QMessageBox::critical(this, windowTitle(), tr("No active document available")); return; } std::string type, objName; App::DocumentObject* obj1 = activeDoc->getObject(shapeOne.c_str()); App::DocumentObject* obj2 = activeDoc->getObject(shapeTwo.c_str()); if (!obj1 || !obj2) { // objects don't exists (anymore) QMessageBox::critical(this, windowTitle(), tr("One of the selected objects doesn't exist anymore")); return; } if (ui->unionButton->isChecked()) { if (!hasSolids(obj1) || !hasSolids(obj2)) { QMessageBox::critical(this, windowTitle(), tr("Performing union on non-solids is not possible")); return; } type = "Part::Fuse"; objName = activeDoc->getUniqueObjectName("Fusion"); } else if (ui->interButton->isChecked()) { if (!hasSolids(obj1) || !hasSolids(obj2)) { QMessageBox::critical(this, windowTitle(), tr("Performing intersection on non-solids is not possible")); return; } type = "Part::Common"; objName = activeDoc->getUniqueObjectName("Common"); } else if (ui->diffButton->isChecked()) { if (!hasSolids(obj1) || !hasSolids(obj2)) { QMessageBox::critical(this, windowTitle(), tr("Performing difference on non-solids is not possible")); return; } type = "Part::Cut"; objName = activeDoc->getUniqueObjectName("Cut"); } else if (ui->sectionButton->isChecked()) { type = "Part::Section"; objName = activeDoc->getUniqueObjectName("Section"); } try { Gui::WaitCursor wc; activeDoc->openTransaction("Boolean operation"); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject(\"%s\",\"%s\")", type.c_str(), objName.c_str()); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Base = App.activeDocument().%s", objName.c_str(),shapeOne.c_str()); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Tool = App.activeDocument().%s", objName.c_str(),shapeTwo.c_str()); Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().hide(\"%s\")",shapeOne.c_str()); Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().hide(\"%s\")",shapeTwo.c_str()); Gui::Command::copyVisual(objName.c_str(), "ShapeColor", shapeOne.c_str()); Gui::Command::copyVisual(objName.c_str(), "DisplayMode", shapeOne.c_str()); activeDoc->commitTransaction(); activeDoc->recompute(); } catch (const Base::Exception& e) { e.ReportException(); } } // --------------------------------------- TaskBooleanOperation::TaskBooleanOperation() { widget = new DlgBooleanOperation(); taskbox = new Gui::TaskView::TaskBox( Gui::BitmapFactory().pixmap("Part_Booleans"), widget->windowTitle(), false, 0); taskbox->groupLayout()->addWidget(widget); Content.push_back(taskbox); } TaskBooleanOperation::~TaskBooleanOperation() { // automatically deleted in the sub-class } void TaskBooleanOperation::clicked(int id) { if (id == QDialogButtonBox::Apply) { widget->accept(); } } #include "moc_DlgBooleanOperation.cpp"