From 4dee80f4e121541801fd4d8552e66ba26dc2c9b5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 25 Jul 2014 13:35:10 +0200 Subject: [PATCH] + support to create faces from vertices with shape builder --- src/Mod/Part/App/AppPartPy.cpp | 10 +- src/Mod/Part/Gui/TaskShapeBuilder.cpp | 137 +++++++++++++++++++++----- src/Mod/Part/Gui/TaskShapeBuilder.h | 9 +- src/Mod/Part/Gui/TaskShapeBuilder.ui | 76 +++++++++----- 4 files changed, 176 insertions(+), 56 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 40769686d..bd5d787e9 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -1022,7 +1022,8 @@ static PyObject * makeLine(PyObject *self, PyObject *args) static PyObject * makePolygon(PyObject *self, PyObject *args) { PyObject *pcObj; - if (!PyArg_ParseTuple(args, "O", &pcObj)) // convert args: Python->C + PyObject *pclosed=Py_False; + if (!PyArg_ParseTuple(args, "O|O!", &pcObj, &(PyBool_Type), &pclosed)) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { @@ -1048,6 +1049,13 @@ static PyObject * makePolygon(PyObject *self, PyObject *args) if (!mkPoly.IsDone()) Standard_Failure::Raise("Cannot create polygon because less than two vertices are given"); + // if the polygon should be closed + if (PyObject_IsTrue(pclosed)) { + if (!mkPoly.FirstVertex().IsSame(mkPoly.LastVertex())) { + mkPoly.Add(mkPoly.FirstVertex()); + } + } + return new TopoShapeWirePy(new TopoShape(mkPoly.Wire())); } catch (Standard_Failure) { diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.cpp b/src/Mod/Part/Gui/TaskShapeBuilder.cpp index 1d37534be..6dddd4023 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.cpp +++ b/src/Mod/Part/Gui/TaskShapeBuilder.cpp @@ -110,10 +110,11 @@ ShapeBuilderWidget::ShapeBuilderWidget(QWidget* parent) d->ui.setupUi(this); d->ui.label->setText(QString()); - d->bg.addButton(d->ui.radioButtonEdge, 0); - d->bg.addButton(d->ui.radioButtonFace, 1); - d->bg.addButton(d->ui.radioButtonShell, 2); - d->bg.addButton(d->ui.radioButtonSolid, 3); + d->bg.addButton(d->ui.radioButtonEdgeFromVertex, 0); + d->bg.addButton(d->ui.radioButtonFaceFromVertex, 1); + d->bg.addButton(d->ui.radioButtonFaceFromEdge, 2); + d->bg.addButton(d->ui.radioButtonShellFromFace, 3); + d->bg.addButton(d->ui.radioButtonSolidFromShell, 4); d->bg.setExclusive(true); connect(&d->bg, SIGNAL(buttonClicked(int)), @@ -140,25 +141,29 @@ void ShapeBuilderWidget::on_createButton_clicked() try { if (mode == 0) { - createEdge(); + createEdgeFromVertex(); } else if (mode == 1) { - createFace(); + createFaceFromVertex(); } else if (mode == 2) { - createShell(); + createFaceFromEdge(); } else if (mode == 3) { - createSolid(); + createShellFromFace(); + } + else if (mode == 4) { + createSolidFromShell(); } doc->getDocument()->recompute(); + Gui::Selection().clearSelection(); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); } } -void ShapeBuilderWidget::createEdge() +void ShapeBuilderWidget::createEdgeFromVertex() { Gui::SelectionFilter vertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 2"); bool matchVertex = vertexFilter.match(); @@ -194,12 +199,70 @@ void ShapeBuilderWidget::createEdge() "del _\n" ).arg(elements[0]).arg(elements[1]); - Gui::Application::Instance->activeDocument()->openCommand("Edge"); - Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); - Gui::Application::Instance->activeDocument()->commitCommand(); + try { + Gui::Application::Instance->activeDocument()->openCommand("Edge"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + Gui::Application::Instance->activeDocument()->commitCommand(); + } + catch (const Base::Exception&) { + Gui::Application::Instance->activeDocument()->abortCommand(); + throw; + } } -void ShapeBuilderWidget::createFace() +void ShapeBuilderWidget::createFaceFromVertex() +{ + Gui::SelectionFilter vertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 3.."); + bool matchVertex = vertexFilter.match(); + if (!matchVertex) { + QMessageBox::critical(this, tr("Wrong selection"), tr("Select three or more vertices")); + return; + } + + std::vector sel = vertexFilter.Result[0]; + std::vector::iterator it; + std::vector::const_iterator jt; + + QString list; + QTextStream str(&list); + str << "["; + for (it=sel.begin();it!=sel.end();++it) { + for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) { + str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ".Point, "; + } + } + str << "]"; + + QString cmd; + if (d->ui.checkPlanar->isChecked()) { + cmd = QString::fromAscii( + "_=Part.Face(Part.makePolygon(%1, True))\n" + "if _.isNull(): raise Exception('Failed to create face')\n" + "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n" + "del _\n" + ).arg(list); + } + else { + cmd = QString::fromAscii( + "_=Part.makeFilledFace([Part.makePolygon(%1, True)])\n" + "if _.isNull(): raise Exception('Failed to create face')\n" + "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n" + "del _\n" + ).arg(list); + } + + try { + Gui::Application::Instance->activeDocument()->openCommand("Face"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + Gui::Application::Instance->activeDocument()->commitCommand(); + } + catch (const Base::Exception&) { + Gui::Application::Instance->activeDocument()->abortCommand(); + throw; + } +} + +void ShapeBuilderWidget::createFaceFromEdge() { Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1.."); bool matchEdge = edgeFilter.match(); @@ -240,12 +303,18 @@ void ShapeBuilderWidget::createFace() ).arg(list); } - Gui::Application::Instance->activeDocument()->openCommand("Face"); - Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); - Gui::Application::Instance->activeDocument()->commitCommand(); + try { + Gui::Application::Instance->activeDocument()->openCommand("Face"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + Gui::Application::Instance->activeDocument()->commitCommand(); + } + catch (const Base::Exception&) { + Gui::Application::Instance->activeDocument()->abortCommand(); + throw; + } } -void ShapeBuilderWidget::createShell() +void ShapeBuilderWidget::createShellFromFace() { Gui::SelectionFilter faceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 2.."); bool matchFace = faceFilter.match(); @@ -287,12 +356,18 @@ void ShapeBuilderWidget::createShell() "del _\n" ).arg(list); - Gui::Application::Instance->activeDocument()->openCommand("Shell"); - Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); - Gui::Application::Instance->activeDocument()->commitCommand(); + try { + Gui::Application::Instance->activeDocument()->openCommand("Shell"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + Gui::Application::Instance->activeDocument()->commitCommand(); + } + catch (const Base::Exception&) { + Gui::Application::Instance->activeDocument()->abortCommand(); + throw; + } } -void ShapeBuilderWidget::createSolid() +void ShapeBuilderWidget::createSolidFromShell() { Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1"); bool matchPart = partFilter.match(); @@ -321,9 +396,15 @@ void ShapeBuilderWidget::createSolid() "del _\n" ).arg(line); - Gui::Application::Instance->activeDocument()->openCommand("Solid"); - Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); - Gui::Application::Instance->activeDocument()->commitCommand(); + try { + Gui::Application::Instance->activeDocument()->openCommand("Solid"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + Gui::Application::Instance->activeDocument()->commitCommand(); + } + catch (const Base::Exception&) { + Gui::Application::Instance->activeDocument()->abortCommand(); + throw; + } } void ShapeBuilderWidget::switchMode(int mode) @@ -336,12 +417,18 @@ void ShapeBuilderWidget::switchMode(int mode) d->ui.checkFaces->setEnabled(false); } else if (mode == 1) { + d->gate->setMode(ShapeSelection::VERTEX); + d->ui.label->setText(tr("Select a list of vertices")); + d->ui.checkPlanar->setEnabled(true); + d->ui.checkFaces->setEnabled(false); + } + else if (mode == 2) { d->gate->setMode(ShapeSelection::EDGE); d->ui.label->setText(tr("Select a closed set of edges")); d->ui.checkPlanar->setEnabled(true); d->ui.checkFaces->setEnabled(false); } - else if (mode == 2) { + else if (mode == 3) { d->gate->setMode(ShapeSelection::FACE); d->ui.label->setText(tr("Select adjacent faces")); d->ui.checkPlanar->setEnabled(false); diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.h b/src/Mod/Part/Gui/TaskShapeBuilder.h index c2777d04e..c2682f278 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.h +++ b/src/Mod/Part/Gui/TaskShapeBuilder.h @@ -45,10 +45,11 @@ private Q_SLOTS: void switchMode(int); private: - void createEdge(); - void createFace(); - void createShell(); - void createSolid(); + void createEdgeFromVertex(); + void createFaceFromVertex(); + void createFaceFromEdge(); + void createShellFromFace(); + void createSolidFromShell(); void changeEvent(QEvent *e); private: diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.ui b/src/Mod/Part/Gui/TaskShapeBuilder.ui index 2111f38db..dd1c6584b 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.ui +++ b/src/Mod/Part/Gui/TaskShapeBuilder.ui @@ -6,56 +6,77 @@ 0 0 - 220 - 259 + 182 + 263 Create shape - + Create shape - + Edge from vertices - - + + + + Face from vertices + + + + + Face from edges - + + + + Shell from faces + + + + + + + Solid from shell + + + + + + + Qt::Horizontal + + + + Planar - - + + - Shell from faces + All faces - - - - Solid from shell - - - - + @@ -79,17 +100,10 @@ - - - - All faces - - - - + Qt::Vertical @@ -111,6 +125,16 @@ + + radioButtonEdgeFromVertex + radioButtonFaceFromVertex + checkPlanar + radioButtonFaceFromEdge + radioButtonShellFromFace + checkFaces + radioButtonSolidFromShell + createButton +