diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 7f60c9958..7cdf562ca 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -167,6 +167,7 @@ void PartExport initPart() Part::Part2DObject ::init(); Part::Part2DObjectPython ::init(); Part::RuledSurface ::init(); + Part::Loft ::init(); // Geometry types Part::Geometry ::init(); diff --git a/src/Mod/Part/App/Features.cpp b/src/Mod/Part/App/Features.cpp index 029bfc868..7e603ee5e 100644 --- a/src/Mod/Part/App/Features.cpp +++ b/src/Mod/Part/App/Features.cpp @@ -101,3 +101,67 @@ App::DocumentObjectExecReturn *RuledSurface::execute(void) return new App::DocumentObjectExecReturn(e->GetMessageString()); } } + +// ---------------------------------------------------------------------------- + +PROPERTY_SOURCE(Part::Loft, Part::Feature) + +Loft::Loft() +{ + ADD_PROPERTY_TYPE(Sections,(0),"Loft",App::Prop_None,"List of sections"); + Sections.setSize(0); + ADD_PROPERTY_TYPE(Solid,(false),"Loft",App::Prop_None,"Create solid"); + ADD_PROPERTY_TYPE(Ruled,(false),"Loft",App::Prop_None,"Ruled surface"); +} + +short Loft::mustExecute() const +{ + if (Sections.isTouched()) + return 1; + if (Solid.isTouched()) + return 1; + if (Ruled.isTouched()) + return 1; + return 0; +} + +void Loft::onChanged(const App::Property* prop) +{ + Part::Feature::onChanged(prop); +} + +App::DocumentObjectExecReturn *Loft::execute(void) +{ + if (Sections.getSize() == 0) + return new App::DocumentObjectExecReturn("No sections linked."); + + try { + TopTools_ListOfShape profiles; + const std::vector& shapes = Sections.getValues(); + std::vector::const_iterator it; + for (it = shapes.begin(); it != shapes.end(); ++it) { + if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a shape."); + const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape is invalid."); + if (shape.ShapeType() == TopAbs_WIRE) + profiles.Append(shape); + else if (shape.ShapeType() == TopAbs_EDGE) + profiles.Append(shape); + else + return new App::DocumentObjectExecReturn("Linked shape is neither a vertex nor a wire."); + } + + Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; + Standard_Boolean isRuled = Ruled.getValue() ? Standard_True : Standard_False; + + TopoShape myShape; + this->Shape.setValue(myShape.makeLoft(profiles, isSolid, isRuled)); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} diff --git a/src/Mod/Part/App/Features.h b/src/Mod/Part/App/Features.h index f83c71817..f01fde575 100644 --- a/src/Mod/Part/App/Features.h +++ b/src/Mod/Part/App/Features.h @@ -51,6 +51,28 @@ protected: void onChanged (const App::Property* prop); }; +class Loft : public Part::Feature +{ + PROPERTY_HEADER(Part::Loft); + +public: + Loft(); + + App::PropertyLinkList Sections; + App::PropertyBool Solid; + App::PropertyBool Ruled; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} + +protected: + void onChanged (const App::Property* prop); +}; + } //namespace Part diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index e740c6306..cadc2fcf5 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -40,6 +40,7 @@ set(PartGui_MOC_HDRS DlgSettingsGeneral.h TaskFaceColors.h TaskShapeBuilder.h + TaskLoft.h ) fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS}) @@ -62,6 +63,7 @@ set(PartGui_UIC_SRCS DlgSettingsGeneral.ui TaskFaceColors.ui TaskShapeBuilder.ui + TaskLoft.ui ) qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS}) @@ -148,6 +150,9 @@ SET(PartGui_SRCS TaskShapeBuilder.cpp TaskShapeBuilder.h TaskShapeBuilder.ui + TaskLoft.cpp + TaskLoft.h + TaskLoft.ui ) SET(PartGui_Scripts diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index a4b31f52a..4277a308e 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -58,6 +58,7 @@ #include "Mirroring.h" #include "ViewProvider.h" #include "TaskShapeBuilder.h" +#include "TaskLoft.h" //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -903,6 +904,31 @@ bool CmdPartBuilder::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdPartLoft); + +CmdPartLoft::CmdPartLoft() + : Command("Part_Loft") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Loft..."); + sToolTipText = QT_TR_NOOP("Advanced utility to lofts"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; +} + +void CmdPartLoft::activated(int iMsg) +{ + Gui::Control().showDialog(new PartGui::TaskLoft()); +} + +bool CmdPartLoft::isActive(void) +{ + return (hasActiveDocument() && !Gui::Control().activeDialog()); +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdShapeInfo); CmdShapeInfo::CmdShapeInfo() @@ -1133,5 +1159,6 @@ void CreatePartCommands(void) rcCmdMgr.addCommand(new CmdShapeInfo()); rcCmdMgr.addCommand(new CmdPartRuledSurface()); rcCmdMgr.addCommand(new CmdPartBuilder()); + rcCmdMgr.addCommand(new CmdPartLoft()); } diff --git a/src/Mod/Part/Gui/Makefile.am b/src/Mod/Part/Gui/Makefile.am index 53121a531..c277b56ca 100644 --- a/src/Mod/Part/Gui/Makefile.am +++ b/src/Mod/Part/Gui/Makefile.am @@ -17,6 +17,7 @@ BUILT_SOURCES=\ ui_Mirroring.h \ ui_TaskFaceColors.h \ ui_TaskShapeBuilder.h \ + ui_TaskLoft.h \ moc_CrossSections.cpp \ moc_DlgBooleanOperation.cpp \ moc_DlgExtrusion.cpp \ @@ -32,6 +33,7 @@ BUILT_SOURCES=\ moc_Mirroring.cpp \ moc_TaskFaceColors.cpp \ moc_TaskShapeBuilder.cpp \ + moc_TaskLoft.cpp \ qrc_Part.cpp libPartGui_la_SOURCES=\ @@ -68,6 +70,8 @@ libPartGui_la_SOURCES=\ TaskFaceColors.h \ TaskShapeBuilder.cpp \ TaskShapeBuilder.h \ + TaskLoft.cpp \ + TaskLoft.h \ PreCompiled.cpp \ PreCompiled.h \ SoBrepShape.cpp \ @@ -215,6 +219,7 @@ EXTRA_DIST = \ Mirroring.ui \ TaskFaceColors.ui \ TaskShapeBuilder.ui \ + TaskLoft.ui \ Resources/Part.qrc \ Resources/translations/Part_af.qm \ Resources/translations/Part_af.ts \ diff --git a/src/Mod/Part/Gui/TaskLoft.cpp b/src/Mod/Part/Gui/TaskLoft.cpp new file mode 100644 index 000000000..7a6f22f9b --- /dev/null +++ b/src/Mod/Part/Gui/TaskLoft.cpp @@ -0,0 +1,270 @@ +/*************************************************************************** + * Copyright (c) 2011 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 +#endif + +#include "ui_TaskLoft.h" +#include "TaskLoft.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace PartGui; + +class LoftWidget::Private +{ +public: + Ui_TaskLoft ui; + std::string document; + Private() + { + } + ~Private() + { + } +}; + +/* TRANSLATOR PartGui::LoftWidget */ + +LoftWidget::LoftWidget(QWidget* parent) + : d(new Private()) +{ + Gui::Application::Instance->runPythonCode("from FreeCAD import Base"); + Gui::Application::Instance->runPythonCode("import Part"); + + d->ui.setupUi(this); + connect(d->ui.treeWidgetWire, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + connect(d->ui.treeWidgetLoft, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + findShapes(); +} + +LoftWidget::~LoftWidget() +{ + delete d; +} + +void LoftWidget::findShapes() +{ + App::Document* activeDoc = App::GetApplication().getActiveDocument(); + Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); + if (!activeGui) return; + d->document = activeDoc->getName(); + + std::vector objs = activeDoc->getObjectsOfType(); + + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { + const TopoDS_Shape& shape = (*it)->Shape.getValue(); + if (shape.IsNull()) continue; + + if (shape.ShapeType() == TopAbs_WIRE || shape.ShapeType() == TopAbs_VERTEX) { + QString label = QString::fromUtf8((*it)->Label.getValue()); + QString name = QString::fromAscii((*it)->getNameInDocument()); + + QTreeWidgetItem* child = new QTreeWidgetItem(); + 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()); + d->ui.treeWidgetWire->addTopLevelItem(child); + } + } +} + +bool LoftWidget::accept() +{ + QString list, solid, ruled; + if (d->ui.checkSolid->isChecked()) + solid = QString::fromAscii("True"); + else + solid = QString::fromAscii("False"); + + if (d->ui.checkRuledSurface->isChecked()) + ruled = QString::fromAscii("True"); + else + ruled = QString::fromAscii("False"); + + QTextStream str(&list); + + int count = d->ui.treeWidgetLoft->topLevelItemCount(); + if (count < 2) { + QMessageBox::critical(this, tr("Too few elements"), tr("At least two vertices or wires are rquired.")); + return false; + } + for (int i=0; iui.treeWidgetLoft->topLevelItem(i); + QString name = child->data(0, Qt::UserRole).toString(); + str << "App.getDocument('" << d->document.c_str() << "')." << name << ", "; + } + + try { + QString cmd; + cmd = QString::fromAscii( + "App.getDocument('%4').addObject('Part::Loft','Loft')\n" + "App.getDocument('%4').ActiveObject.Sections=[%1]\n" + "App.getDocument('%4').ActiveObject.Solid=%2\n" + "App.getDocument('%4').ActiveObject.Ruled=%3\n" + ).arg(list).arg(solid).arg(ruled).arg(QString::fromAscii(d->document.c_str())); + + Gui::Document* doc = Gui::Application::Instance->getDocument(d->document.c_str()); + if (!doc) throw Base::Exception("Document doesn't exist anymore"); + doc->openCommand("Loft"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + doc->commitCommand(); + doc->getDocument()->recompute(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + return false; + } + + return true; +} + +bool LoftWidget::reject() +{ + return true; +} + +void LoftWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) +{ + if (previous) { + Gui::Selection().rmvSelection(d->document.c_str(), + (const char*)previous->data(0,Qt::UserRole).toByteArray()); + } + if (current) { + Gui::Selection().addSelection(d->document.c_str(), + (const char*)current->data(0,Qt::UserRole).toByteArray()); + } +} + +void LoftWidget::on_addButton_clicked() +{ + QTreeWidgetItem* item = d->ui.treeWidgetWire->currentItem(); + if (item) { + int index = d->ui.treeWidgetWire->indexOfTopLevelItem(item); + item = d->ui.treeWidgetWire->takeTopLevelItem(index); + d->ui.treeWidgetWire->setCurrentItem(0); + d->ui.treeWidgetLoft->addTopLevelItem(item); + d->ui.treeWidgetLoft->setCurrentItem(item); + } +} + +void LoftWidget::on_removeButton_clicked() +{ + QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); + if (item) { + int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); + item = d->ui.treeWidgetLoft->takeTopLevelItem(index); + d->ui.treeWidgetLoft->setCurrentItem(0); + d->ui.treeWidgetWire->addTopLevelItem(item); + d->ui.treeWidgetWire->setCurrentItem(item); + } +} + +void LoftWidget::on_upButton_clicked() +{ + QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); + if (item && d->ui.treeWidgetLoft->isItemSelected(item)) { + int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); + if (index > 0) { + d->ui.treeWidgetLoft->takeTopLevelItem(index); + d->ui.treeWidgetLoft->insertTopLevelItem(index-1, item); + d->ui.treeWidgetLoft->setCurrentItem(item); + } + } +} + +void LoftWidget::on_downButton_clicked() +{ + QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); + if (item && d->ui.treeWidgetLoft->isItemSelected(item)) { + int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); + if (index < d->ui.treeWidgetLoft->topLevelItemCount()-1) { + d->ui.treeWidgetLoft->takeTopLevelItem(index); + d->ui.treeWidgetLoft->insertTopLevelItem(index+1, item); + d->ui.treeWidgetLoft->setCurrentItem(item); + } + } +} + +void LoftWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + d->ui.retranslateUi(this); + } +} + + +/* TRANSLATOR PartGui::TaskLoft */ + +TaskLoft::TaskLoft() +{ + widget = new LoftWidget(); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskLoft::~TaskLoft() +{ +} + +void TaskLoft::open() +{ +} + +void TaskLoft::clicked(int) +{ +} + +bool TaskLoft::accept() +{ + return widget->accept(); +} + +bool TaskLoft::reject() +{ + return widget->reject(); +} + +#include "moc_TaskLoft.cpp" diff --git a/src/Mod/Part/Gui/TaskLoft.h b/src/Mod/Part/Gui/TaskLoft.h new file mode 100644 index 000000000..82ac877a5 --- /dev/null +++ b/src/Mod/Part/Gui/TaskLoft.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (c) 2011 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 * + * * + ***************************************************************************/ + + +#ifndef PARTGUI_TASKLOFT_H +#define PARTGUI_TASKLOFT_H + +#include +#include + +class QTreeWidgetItem; + +namespace PartGui { + +class LoftWidget : public QWidget +{ + Q_OBJECT + +public: + LoftWidget(QWidget* parent = 0); + ~LoftWidget(); + + bool accept(); + bool reject(); + +private Q_SLOTS: + void on_addButton_clicked(); + void on_removeButton_clicked(); + void on_upButton_clicked(); + void on_downButton_clicked(); + void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); + +private: + void changeEvent(QEvent *e); + void findShapes(); + +private: + class Private; + Private* d; +}; + +class TaskLoft : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskLoft(); + ~TaskLoft(); + +public: + void open(); + bool accept(); + bool reject(); + void clicked(int); + + QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +private: + LoftWidget* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace PartGui + +#endif // PARTGUI_TASKLOFT_H diff --git a/src/Mod/Part/Gui/TaskLoft.ui b/src/Mod/Part/Gui/TaskLoft.ui new file mode 100644 index 000000000..1dd0c6159 --- /dev/null +++ b/src/Mod/Part/Gui/TaskLoft.ui @@ -0,0 +1,204 @@ + + + PartGui::TaskLoft + + + + 0 + 0 + 324 + 326 + + + + Loft + + + + + + + Vertex/Wire + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 33 + 58 + + + + + + + + true + + + + 30 + 30 + + + + Move right + + + <b>Move the selected item one level down.</b><p>This will also change the level of the parent item.</p> + + + + + + + :/icons/button_right.xpm:/icons/button_right.xpm + + + + + + + true + + + + 30 + 30 + + + + Move left + + + <b>Move the selected item one level up.</b><p>This will also change the level of the parent item.</p> + + + + + + + :/icons/button_left.xpm:/icons/button_left.xpm + + + true + + + false + + + + + + + true + + + + 30 + 30 + + + + Move up + + + <b>Move the selected item up.</b><p>The item will be moved within the hierarchy level.</p> + + + + + + + :/icons/button_up.xpm:/icons/button_up.xpm + + + + + + + true + + + + 30 + 30 + + + + Move down + + + <b>Move the selected item down.</b><p>The item will be moved within the hierarchy level.</p> + + + + + + + :/icons/button_down.xpm:/icons/button_down.xpm + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 33 + 57 + + + + + + + + + + + Loft + + + + + + + + Create solid + + + + + + + Ruled surface + + + + + + + + + + diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.cpp b/src/Mod/Part/Gui/TaskShapeBuilder.cpp index 776569d02..1171940d4 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.cpp +++ b/src/Mod/Part/Gui/TaskShapeBuilder.cpp @@ -99,7 +99,7 @@ public: } }; -/* TRANSLATOR PartGui::TaskShapeBuilder */ +/* TRANSLATOR PartGui::ShapeBuilderWidget */ ShapeBuilderWidget::ShapeBuilderWidget(QWidget* parent) : d(new Private()) diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.h b/src/Mod/Part/Gui/TaskShapeBuilder.h index 30217d569..c2777d04e 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.h +++ b/src/Mod/Part/Gui/TaskShapeBuilder.h @@ -21,8 +21,8 @@ ***************************************************************************/ -#ifndef PARTGUI_TASKSETCOLORS_H -#define PARTGUI_TASKSETCOLORS_H +#ifndef PARTGUI_TASKSHAPEBUILDER_H +#define PARTGUI_TASKSHAPEBUILDER_H #include #include @@ -80,4 +80,4 @@ private: } //namespace PartGui -#endif // PARTGUI_TASKSETCOLORS_H +#endif // PARTGUI_TASKSHAPEBUILDER_H diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp index 14162ff6c..068f1f0ff 100644 --- a/src/Mod/Part/Gui/Workbench.cpp +++ b/src/Mod/Part/Gui/Workbench.cpp @@ -66,7 +66,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Part_MakeSolid" << "Part_ReverseShape" << "Part_SimpleCopy" << "Separator" << "Part_Boolean" << "Part_CrossSections" << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" - << "Part_RuledSurface" << "Part_Builder" << "Separator" << "Part_ShapeInfo"; + << "Part_RuledSurface" << "Part_Loft" + << "Part_Builder" << "Separator" << "Part_ShapeInfo"; Gui::MenuItem* partSimple = new Gui::MenuItem; root->insertItem(item, partSimple);