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
00026 #ifndef _PreComp_
00027 # include <TopExp_Explorer.hxx>
00028 # include <TopTools_IndexedMapOfShape.hxx>
00029 # include <QButtonGroup>
00030 # include <QMessageBox>
00031 # include <QTextStream>
00032 #endif
00033
00034 #include "ui_TaskShapeBuilder.h"
00035 #include "TaskShapeBuilder.h"
00036 #include "ViewProviderExt.h"
00037
00038 #include <Gui/Application.h>
00039 #include <Gui/BitmapFactory.h>
00040 #include <Gui/Document.h>
00041 #include <Gui/Selection.h>
00042 #include <Gui/SelectionFilter.h>
00043
00044 #include <Base/Console.h>
00045 #include <Base/Interpreter.h>
00046 #include <App/Application.h>
00047 #include <App/Document.h>
00048 #include <App/DocumentObject.h>
00049 #include <Mod/Part/App/PartFeature.h>
00050
00051
00052 using namespace PartGui;
00053
00054 namespace PartGui {
00055 class ShapeSelection : public Gui::SelectionFilterGate
00056 {
00057 public:
00058 enum Type {VERTEX, EDGE, FACE, ALL};
00059 Type mode;
00060 ShapeSelection()
00061 : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), mode(ALL)
00062 {
00063 }
00064 void setMode(Type mode)
00065 {
00066 this->mode = mode;
00067 }
00068 bool allow(App::Document*, App::DocumentObject* obj, const char*sSubName)
00069 {
00070 if (!obj || !obj->isDerivedFrom(Part::Feature::getClassTypeId()))
00071 return false;
00072 if (!sSubName || sSubName[0] == '\0')
00073 return (mode == ALL);
00074 std::string element(sSubName);
00075 switch (mode) {
00076 case VERTEX:
00077 return element.substr(0,6) == "Vertex";
00078 case EDGE:
00079 return element.substr(0,4) == "Edge";
00080 case FACE:
00081 return element.substr(0,4) == "Face";
00082 default:
00083 return true;
00084 }
00085 }
00086 };
00087 }
00088
00089 class ShapeBuilderWidget::Private
00090 {
00091 public:
00092 Ui_TaskShapeBuilder ui;
00093 QButtonGroup bg;
00094 ShapeSelection* gate;
00095 Private()
00096 {
00097 }
00098 ~Private()
00099 {
00100 }
00101 };
00102
00103
00104
00105 ShapeBuilderWidget::ShapeBuilderWidget(QWidget* parent)
00106 : d(new Private())
00107 {
00108 Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
00109 Gui::Application::Instance->runPythonCode("import Part");
00110
00111 d->ui.setupUi(this);
00112 d->ui.label->setText(QString());
00113 d->bg.addButton(d->ui.radioButtonEdge, 0);
00114 d->bg.addButton(d->ui.radioButtonFace, 1);
00115 d->bg.addButton(d->ui.radioButtonShell, 2);
00116 d->bg.addButton(d->ui.radioButtonSolid, 3);
00117 d->bg.setExclusive(true);
00118
00119 connect(&d->bg, SIGNAL(buttonClicked(int)),
00120 this, SLOT(switchMode(int)));
00121
00122 d->gate = new ShapeSelection();
00123 Gui::Selection().addSelectionGate(d->gate);
00124
00125 d->bg.button(0)->setChecked(true);
00126 switchMode(0);
00127 }
00128
00129 ShapeBuilderWidget::~ShapeBuilderWidget()
00130 {
00131 Gui::Selection().rmvSelectionGate();
00132 delete d;
00133 }
00134
00135 void ShapeBuilderWidget::on_createButton_clicked()
00136 {
00137 int mode = d->bg.checkedId();
00138 Gui::Document* doc = Gui::Application::Instance->activeDocument();
00139 if (!doc) return;
00140
00141 try {
00142 if (mode == 0) {
00143 createEdge();
00144 }
00145 else if (mode == 1) {
00146 createFace();
00147 }
00148 else if (mode == 2) {
00149 createShell();
00150 }
00151 else if (mode == 3) {
00152 createSolid();
00153 }
00154 doc->getDocument()->recompute();
00155 }
00156 catch (const Base::Exception& e) {
00157 Base::Console().Error("%s\n", e.what());
00158 }
00159 }
00160
00161 void ShapeBuilderWidget::createEdge()
00162 {
00163 Gui::SelectionFilter vertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 2");
00164 bool matchVertex = vertexFilter.match();
00165 if (!matchVertex) {
00166 QMessageBox::critical(this, tr("Wrong selection"), tr("Select two vertices"));
00167 return;
00168 }
00169
00170 std::vector<Gui::SelectionObject> sel = vertexFilter.Result[0];
00171 std::vector<QString> elements;
00172 std::vector<Gui::SelectionObject>::iterator it;
00173 std::vector<std::string>::const_iterator jt;
00174 for (it=sel.begin();it!=sel.end();++it) {
00175 for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00176 QString line;
00177 QTextStream str(&line);
00178 str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ".Point";
00179 elements.push_back(line);
00180 }
00181 }
00182
00183
00184 if (elements.size() != 2) {
00185 QMessageBox::critical(this, tr("Wrong selection"), tr("Select two vertices"));
00186 return;
00187 }
00188
00189 QString cmd;
00190 cmd = QString::fromAscii(
00191 "_=Part.makeLine(%1, %2)\n"
00192 "if _.isNull(): raise Exception('Failed to create edge')\n"
00193 "App.ActiveDocument.addObject('Part::Feature','Edge').Shape=_\n"
00194 "del _\n"
00195 ).arg(elements[0]).arg(elements[1]);
00196
00197 Gui::Application::Instance->activeDocument()->openCommand("Edge");
00198 Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00199 Gui::Application::Instance->activeDocument()->commitCommand();
00200 }
00201
00202 void ShapeBuilderWidget::createFace()
00203 {
00204 Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 3..");
00205 bool matchEdge = edgeFilter.match();
00206 if (!matchEdge) {
00207 QMessageBox::critical(this, tr("Wrong selection"), tr("Select three or more edges"));
00208 return;
00209 }
00210
00211 std::vector<Gui::SelectionObject> sel = edgeFilter.Result[0];
00212 std::vector<Gui::SelectionObject>::iterator it;
00213 std::vector<std::string>::const_iterator jt;
00214
00215 QString list;
00216 QTextStream str(&list);
00217 str << "[";
00218 for (it=sel.begin();it!=sel.end();++it) {
00219 for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00220 str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ", ";
00221 }
00222 }
00223 str << "]";
00224
00225 QString cmd;
00226 if (d->ui.checkPlanar->isChecked()) {
00227 cmd = QString::fromAscii(
00228 "_=Part.Face(Part.Wire(Part.__sortEdges__(%1)))\n"
00229 "if _.isNull(): raise Exception('Failed to create face')\n"
00230 "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n"
00231 "del _\n"
00232 ).arg(list);
00233 }
00234 else {
00235 cmd = QString::fromAscii(
00236 "_=Part.makeFilledFace(Part.__sortEdges__(%1))\n"
00237 "if _.isNull(): raise Exception('Failed to create face')\n"
00238 "App.ActiveDocument.addObject('Part::Feature','Face').Shape=_\n"
00239 "del _\n"
00240 ).arg(list);
00241 }
00242
00243 Gui::Application::Instance->activeDocument()->openCommand("Face");
00244 Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00245 Gui::Application::Instance->activeDocument()->commitCommand();
00246 }
00247
00248 void ShapeBuilderWidget::createShell()
00249 {
00250 Gui::SelectionFilter faceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 2..");
00251 bool matchFace = faceFilter.match();
00252 if (!matchFace) {
00253 QMessageBox::critical(this, tr("Wrong selection"), tr("Select two or more faces"));
00254 return;
00255 }
00256
00257 std::vector<Gui::SelectionObject> sel = faceFilter.Result[0];
00258 std::vector<Gui::SelectionObject>::iterator it;
00259 std::vector<std::string>::const_iterator jt;
00260
00261 QString list;
00262 QTextStream str(&list);
00263 if (d->ui.checkFaces->isChecked()) {
00264 std::set<App::DocumentObject*> obj;
00265 for (it=sel.begin();it!=sel.end();++it)
00266 obj.insert(it->getObject());
00267 str << "[]";
00268 for (std::set<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) {
00269 str << "+ App.ActiveDocument." << (*it)->getNameInDocument() << ".Shape.Faces";
00270 }
00271 }
00272 else {
00273 str << "[";
00274 for (it=sel.begin();it!=sel.end();++it) {
00275 for (jt=it->getSubNames().begin();jt!=it->getSubNames().end();++jt) {
00276 str << "App.ActiveDocument." << it->getFeatName() << ".Shape." << jt->c_str() << ", ";
00277 }
00278 }
00279 str << "]";
00280 }
00281
00282 QString cmd;
00283 cmd = QString::fromAscii(
00284 "_=Part.Shell(%1)\n"
00285 "if _.isNull(): raise Exception('Failed to create shell')\n"
00286 "App.ActiveDocument.addObject('Part::Feature','Shell').Shape=_\n"
00287 "del _\n"
00288 ).arg(list);
00289
00290 Gui::Application::Instance->activeDocument()->openCommand("Shell");
00291 Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00292 Gui::Application::Instance->activeDocument()->commitCommand();
00293 }
00294
00295 void ShapeBuilderWidget::createSolid()
00296 {
00297 Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1");
00298 bool matchPart = partFilter.match();
00299 if (!matchPart) {
00300 QMessageBox::critical(this, tr("Wrong selection"), tr("Select only one part object"));
00301 return;
00302 }
00303
00304 QString line;
00305 QTextStream str(&line);
00306
00307 std::vector<Gui::SelectionObject> sel = partFilter.Result[0];
00308 std::vector<Gui::SelectionObject>::iterator it;
00309 for (it=sel.begin();it!=sel.end();++it) {
00310 str << "App.ActiveDocument." << it->getFeatName() << ".Shape";
00311 break;
00312 }
00313
00314 QString cmd;
00315 cmd = QString::fromAscii(
00316 "shell=%1\n"
00317 "if shell.ShapeType != 'Shell': raise Exception('Part object is not a shell')\n"
00318 "_=Part.Solid(shell)\n"
00319 "if _.isNull(): raise Exception('Failed to create solid')\n"
00320 "App.ActiveDocument.addObject('Part::Feature','Solid').Shape=_\n"
00321 "del _\n"
00322 ).arg(line);
00323
00324 Gui::Application::Instance->activeDocument()->openCommand("Solid");
00325 Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
00326 Gui::Application::Instance->activeDocument()->commitCommand();
00327 }
00328
00329 void ShapeBuilderWidget::switchMode(int mode)
00330 {
00331 Gui::Selection().clearSelection();
00332 if (mode == 0) {
00333 d->gate->setMode(ShapeSelection::VERTEX);
00334 d->ui.label->setText(tr("Select two vertices to create an edge"));
00335 d->ui.checkPlanar->setEnabled(false);
00336 d->ui.checkFaces->setEnabled(false);
00337 }
00338 else if (mode == 1) {
00339 d->gate->setMode(ShapeSelection::EDGE);
00340 d->ui.label->setText(tr("Select a closed set of edges"));
00341 d->ui.checkPlanar->setEnabled(true);
00342 d->ui.checkFaces->setEnabled(false);
00343 }
00344 else if (mode == 2) {
00345 d->gate->setMode(ShapeSelection::FACE);
00346 d->ui.label->setText(tr("Select adjacent faces"));
00347 d->ui.checkPlanar->setEnabled(false);
00348 d->ui.checkFaces->setEnabled(true);
00349 }
00350 else {
00351 d->gate->setMode(ShapeSelection::ALL);
00352 d->ui.label->setText(tr("All shape types can be selected"));
00353 d->ui.checkPlanar->setEnabled(false);
00354 d->ui.checkFaces->setEnabled(false);
00355 }
00356 }
00357
00358 bool ShapeBuilderWidget::accept()
00359 {
00360 return true;
00361 }
00362
00363 bool ShapeBuilderWidget::reject()
00364 {
00365 return true;
00366 }
00367
00368 void ShapeBuilderWidget::changeEvent(QEvent *e)
00369 {
00370 QWidget::changeEvent(e);
00371 if (e->type() == QEvent::LanguageChange) {
00372 d->ui.retranslateUi(this);
00373 }
00374 }
00375
00376
00377
00378
00379 TaskShapeBuilder::TaskShapeBuilder()
00380 {
00381 widget = new ShapeBuilderWidget();
00382 taskbox = new Gui::TaskView::TaskBox(
00383 Gui::BitmapFactory().pixmap("Part_Shapebuilder"),
00384 widget->windowTitle(), true, 0);
00385 taskbox->groupLayout()->addWidget(widget);
00386 Content.push_back(taskbox);
00387 }
00388
00389 TaskShapeBuilder::~TaskShapeBuilder()
00390 {
00391 }
00392
00393 void TaskShapeBuilder::open()
00394 {
00395 }
00396
00397 void TaskShapeBuilder::clicked(int)
00398 {
00399 }
00400
00401 bool TaskShapeBuilder::accept()
00402 {
00403 return widget->accept();
00404 }
00405
00406 bool TaskShapeBuilder::reject()
00407 {
00408 return widget->reject();
00409 }
00410
00411 #include "moc_TaskShapeBuilder.cpp"