23
#include "PreCompiled.h"
25
# include <QMessageBox>
26
# include <BRep_Tool.hxx>
27
# include <BRepAdaptor_Curve.hxx>
28
# include <Precision.hxx>
29
# include <ShapeExtend_Explorer.hxx>
30
# include <TopExp_Explorer.hxx>
32
# include <TopoDS_Edge.hxx>
33
# include <TopTools_HSequenceOfShape.hxx>
36
#include <App/Application.h>
37
#include <App/Document.h>
38
#include <App/DocumentObject.h>
41
#include <Gui/Application.h>
42
#include <Gui/BitmapFactory.h>
43
#include <Gui/Command.h>
44
#include <Gui/Document.h>
45
#include <Gui/Utilities.h>
46
#include <Gui/ViewProvider.h>
47
#include <Gui/WaitCursor.h>
48
#include <Mod/Part/App/FeatureRevolution.h>
50
#include "DlgRevolution.h"
51
#include "ui_DlgRevolution.h"
54
using namespace PartGui;
56
class DlgRevolution::EdgeSelection : public Gui::SelectionFilterGate
62
: Gui::SelectionFilterGate(nullPointer())
66
bool allow(App::Document* , App::DocumentObject*pObj, const char*sSubName) override
68
this->canSelect = false;
70
if (!sSubName || sSubName[0] == '\0')
72
std::string element(sSubName);
73
if (element.substr(0,4) != "Edge")
75
Part::TopoShape part = Part::Feature::getTopoShape(pObj);
80
TopoDS_Shape sub = part.getSubShape(sSubName);
81
if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) {
82
const TopoDS_Edge& edge = TopoDS::Edge(sub);
83
BRepAdaptor_Curve adapt(edge);
84
if (adapt.GetType() == GeomAbs_Line || adapt.GetType() == GeomAbs_Circle) {
85
this->canSelect = true;
97
DlgRevolution::DlgRevolution(QWidget* parent, Qt::WindowFlags fl)
99
, ui(new Ui_DlgRevolution)
105
ui->xPos->setRange(-DBL_MAX,DBL_MAX);
106
ui->yPos->setRange(-DBL_MAX,DBL_MAX);
107
ui->zPos->setRange(-DBL_MAX,DBL_MAX);
108
ui->xPos->setUnit(Base::Unit::Length);
109
ui->yPos->setUnit(Base::Unit::Length);
110
ui->zPos->setUnit(Base::Unit::Length);
112
ui->xDir->setRange(-DBL_MAX,DBL_MAX);
113
ui->yDir->setRange(-DBL_MAX,DBL_MAX);
114
ui->zDir->setRange(-DBL_MAX,DBL_MAX);
115
ui->xDir->setUnit(Base::Unit());
116
ui->yDir->setUnit(Base::Unit());
117
ui->zDir->setUnit(Base::Unit());
118
ui->zDir->setValue(1.0);
120
ui->angle->setUnit(Base::Unit::Angle);
121
ui->angle->setValue(360.0);
124
Gui::ItemViewSelection sel(ui->treeWidget);
125
sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId()));
126
sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId()));
127
sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId()));
129
connect(ui->txtAxisLink, &QLineEdit::textChanged, this, &DlgRevolution::onAxisLinkTextChanged);
137
DlgRevolution::~DlgRevolution()
140
Gui::Selection().rmvSelectionGate();
143
void DlgRevolution::setupConnections()
146
connect(ui->selectLine, &QPushButton::clicked,
147
this, &DlgRevolution::onSelectLineClicked);
148
connect(ui->btnX, &QPushButton::clicked,
149
this, &DlgRevolution::onButtonXClicked);
150
connect(ui->btnY, &QPushButton::clicked,
151
this, &DlgRevolution::onButtonYClicked);
152
connect(ui->btnZ, &QPushButton::clicked,
153
this, &DlgRevolution::onButtonZClicked);
154
connect(ui->txtAxisLink, &QLineEdit::textChanged,
155
this, &DlgRevolution::onAxisLinkTextChanged);
159
Base::Vector3d DlgRevolution::getDirection() const
161
return Base::Vector3d(
162
ui->xDir->value().getValue(),
163
ui->yDir->value().getValue(),
164
ui->zDir->value().getValue());
167
Base::Vector3d DlgRevolution::getPosition() const
169
return Base::Vector3d(
170
ui->xPos->value().getValueAs(Base::Quantity::MilliMetre),
171
ui->yPos->value().getValueAs(Base::Quantity::MilliMetre),
172
ui->zPos->value().getValueAs(Base::Quantity::MilliMetre));
175
void DlgRevolution::getAxisLink(App::PropertyLinkSub &lnk) const
177
QString text = ui->txtAxisLink->text();
179
if (text.length() == 0) {
180
lnk.setValue(nullptr);
182
QStringList parts = text.split(QChar::fromLatin1(':'));
183
App::DocumentObject* obj = App::GetApplication().getActiveDocument()->getObject(parts[0].toLatin1());
185
throw Base::ValueError(tr("Object not found: %1").arg(parts[0]).toUtf8().constData());
188
if (parts.size() == 1) {
190
} else if (parts.size() == 2) {
191
std::vector<std::string> subs;
192
subs.emplace_back(parts[1].toLatin1().constData());
193
lnk.setValue(obj,subs);
199
double DlgRevolution::getAngle() const
201
return ui->angle->value().getValueAs(Base::Quantity::Degree);
204
void DlgRevolution::setDirection(Base::Vector3d dir)
206
ui->xDir->setValue(dir.x);
207
ui->yDir->setValue(dir.y);
208
ui->zDir->setValue(dir.z);
211
void DlgRevolution::setPosition(Base::Vector3d pos)
213
ui->xPos->setValue(pos.x);
214
ui->yPos->setValue(pos.y);
215
ui->zPos->setValue(pos.z);
218
void DlgRevolution::setAxisLink(const App::PropertyLinkSub& lnk)
220
if (!lnk.getValue()){
221
ui->txtAxisLink->clear();
224
if (lnk.getSubValues().size() == 1){
225
this->setAxisLink(lnk.getValue()->getNameInDocument(), lnk.getSubValues()[0].c_str());
227
this->setAxisLink(lnk.getValue()->getNameInDocument(), "");
231
void DlgRevolution::setAxisLink(const char* objname, const char* subname)
233
if(objname && strlen(objname) > 0){
234
QString txt = QString::fromLatin1(objname);
235
if (subname && strlen(subname) > 0){
236
txt = txt + QString::fromLatin1(":") + QString::fromLatin1(subname);
238
ui->txtAxisLink->setText(txt);
240
ui->txtAxisLink->clear();
244
std::vector<App::DocumentObject*> DlgRevolution::getShapesToRevolve() const
246
QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
247
App::Document* doc = App::GetApplication().getActiveDocument();
249
throw Base::RuntimeError("Document lost");
251
std::vector<App::DocumentObject*> objects;
252
for (auto item : items) {
253
App::DocumentObject* obj = doc->getObject(item->data(0, Qt::UserRole).toString().toLatin1());
255
throw Base::RuntimeError("Object not found");
256
objects.push_back(obj);
261
bool DlgRevolution::validate()
264
if (ui->treeWidget->selectedItems().isEmpty()) {
265
QMessageBox::critical(this, windowTitle(),
266
tr("Select a shape for revolution, first."));
271
bool axisLinkIsValid = false;
272
bool axisLinkHasAngle = false;
274
App::PropertyLinkSub lnk;
275
this->getAxisLink(lnk);
276
double angle_edge = 1e100;
277
Base::Vector3d axis, center;
278
axisLinkIsValid = Part::Revolution::fetchAxisLink(lnk, center, axis, angle_edge);
279
axisLinkHasAngle = angle_edge != 1e100;
280
} catch(Base::Exception &err) {
281
QMessageBox::critical(this, windowTitle(),
282
tr("Revolution axis link is invalid.\n\n%1").arg(QCoreApplication::translate("Exception", err.what())));
283
ui->txtAxisLink->setFocus();
285
} catch(Standard_Failure &err) {
286
QMessageBox::critical(this, windowTitle(),
287
tr("Revolution axis link is invalid.\n\n%1").arg(QString::fromLocal8Bit(err.GetMessageString())));
288
ui->txtAxisLink->setFocus();
291
QMessageBox::critical(this, windowTitle(),
292
tr("Revolution axis link is invalid.\n\n%1").arg(tr("Unknown error")));
293
ui->txtAxisLink->setFocus();
298
if (!axisLinkIsValid){
299
if(this->getDirection().Length() < Precision::Confusion()){
300
QMessageBox::critical(this, windowTitle(),
301
tr("Revolution axis direction is zero-length. It must be non-zero."));
302
ui->xDir->setFocus();
308
if (!axisLinkHasAngle){
309
if (fabs(this->getAngle() / 180.0 * M_PI) < Precision::Angular()) {
310
QMessageBox::critical(this, windowTitle(),
311
tr("Revolution angle span is zero. It must be non-zero."));
312
ui->angle->setFocus();
320
void DlgRevolution::changeEvent(QEvent *e)
322
if (e->type() == QEvent::LanguageChange) {
323
ui->retranslateUi(this);
326
QDialog::changeEvent(e);
330
void DlgRevolution::keyPressEvent(QKeyEvent* ke)
337
void DlgRevolution::findShapes()
339
App::Document* activeDoc = App::GetApplication().getActiveDocument();
342
Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc);
344
std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType<App::DocumentObject>();
346
for (auto obj : objs) {
347
Part::TopoShape topoShape = Part::Feature::getTopoShape(obj);
348
if (topoShape.isNull()) {
351
TopoDS_Shape shape = topoShape.getShape();
352
if (shape.IsNull()) continue;
355
xp.Init(shape,TopAbs_SOLID);
356
if (xp.More()) continue;
357
xp.Init(shape,TopAbs_COMPSOLID);
358
if (xp.More()) continue;
360
QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget);
361
item->setText(0, QString::fromUtf8(obj->Label.getValue()));
362
item->setData(0, Qt::UserRole, QString::fromLatin1(obj->getNameInDocument()));
363
Gui::ViewProvider* vp = activeGui->getViewProvider(obj);
364
if (vp) item->setIcon(0, vp->getIcon());
368
void DlgRevolution::accept()
370
if (!this->validate())
373
App::Document* activeDoc = App::GetApplication().getActiveDocument();
374
activeDoc->openTransaction("Revolve");
377
QString shape, type, name, solid;
378
QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
379
if (ui->checkSolid->isChecked()) {
380
solid = QString::fromLatin1("True");}
382
solid = QString::fromLatin1("False");}
384
App::PropertyLinkSub axisLink;
385
this->getAxisLink(axisLink);
387
if (axisLink.getValue()){
388
strAxisLink = QString::fromLatin1("(App.ActiveDocument.%1, %2)")
389
.arg(QString::fromLatin1(axisLink.getValue()->getNameInDocument()),
390
axisLink.getSubValues().size() == 1 ?
391
QString::fromLatin1("\"%1\"").arg(QString::fromLatin1(axisLink.getSubValues()[0].c_str()))
394
strAxisLink = QString::fromLatin1("None");
398
if (ui->checkSymmetric->isChecked()) {
399
symmetric = QString::fromLatin1("True");}
401
symmetric = QString::fromLatin1("False");}
403
for (auto item : items) {
404
shape = item->data(0, Qt::UserRole).toString();
405
type = QString::fromLatin1("Part::Revolution");
406
name = QString::fromLatin1(activeDoc->getUniqueObjectName("Revolve").c_str());
407
Base::Vector3d axis = this->getDirection();
408
Base::Vector3d pos = this->getPosition();
411
QString code = QString::fromLatin1(
412
"FreeCAD.ActiveDocument.addObject(\"%1\",\"%2\")\n"
413
"FreeCAD.ActiveDocument.%2.Source = FreeCAD.ActiveDocument.%3\n"
414
"FreeCAD.ActiveDocument.%2.Axis = (%4,%5,%6)\n"
415
"FreeCAD.ActiveDocument.%2.Base = (%7,%8,%9)\n"
416
"FreeCAD.ActiveDocument.%2.Angle = %10\n"
417
"FreeCAD.ActiveDocument.%2.Solid = %11\n"
418
"FreeCAD.ActiveDocument.%2.AxisLink = %12\n"
419
"FreeCAD.ActiveDocument.%2.Symmetric = %13\n"
420
"FreeCADGui.ActiveDocument.%3.Visibility = False\n")
421
.arg(type, name, shape)
422
.arg(axis.x,0,'f',15)
423
.arg(axis.y,0,'f',15)
424
.arg(axis.z,0,'f',15)
425
.arg(pos.x, 0,'f',15)
426
.arg(pos.y, 0,'f',15)
427
.arg(pos.z, 0,'f',15)
428
.arg(getAngle(),0,'f',15)
433
Gui::Command::runCommand(Gui::Command::App, code.toLatin1());
434
QByteArray to = name.toLatin1();
435
QByteArray from = shape.toLatin1();
436
Gui::Command::copyVisual(to, "ShapeAppearance", from);
437
Gui::Command::copyVisual(to, "LineColor", from);
438
Gui::Command::copyVisual(to, "PointColor", from);
441
activeDoc->commitTransaction();
442
activeDoc->recompute();
443
} catch (Base::Exception &err) {
444
QMessageBox::critical(this, windowTitle(),
445
tr("Creating Revolve failed.\n\n%1").arg(QCoreApplication::translate("Exception", err.what())));
448
QMessageBox::critical(this, windowTitle(),
449
tr("Creating Revolve failed.\n\n%1").arg(QString::fromUtf8("Unknown error")));
456
void DlgRevolution::onSelectLineClicked()
459
filter = new EdgeSelection();
460
Gui::Selection().addSelectionGate(filter);
461
ui->selectLine->setText(tr("Selecting... (line or arc)"));
463
Gui::Selection().rmvSelectionGate();
465
ui->selectLine->setText(tr("Select reference"));
469
void DlgRevolution::onButtonXClicked()
471
setDirection(Base::Vector3d(1,0,0));
472
if (!ui->xDir->isEnabled())
473
ui->txtAxisLink->clear();
476
void DlgRevolution::onButtonYClicked()
478
setDirection(Base::Vector3d(0,1,0));
479
if (!ui->xDir->isEnabled())
480
ui->txtAxisLink->clear();
483
void DlgRevolution::onButtonZClicked()
485
setDirection(Base::Vector3d(0,0,1));
486
if (!ui->xDir->isEnabled())
487
ui->txtAxisLink->clear();
490
void DlgRevolution::onAxisLinkTextChanged(QString)
494
Base::Vector3d pos, dir;
495
double angle_edge = 1e100;
496
App::PropertyLinkSub lnk; this->getAxisLink(lnk);
497
bool fetched = Part::Revolution::fetchAxisLink(lnk, pos, dir, angle_edge);
499
this->setDirection(dir);
500
this->setPosition(pos);
501
if (angle_edge != 1e100){
502
ui->angle->setValue(0.0);
503
} else if (fabs(ui->angle->value().getValue()) < 1e-12) {
504
ui->angle->setValue(360.0);
508
} catch (Base::Exception &){
513
ui->xDir->setEnabled(en);
514
ui->yDir->setEnabled(en);
515
ui->zDir->setEnabled(en);
516
ui->xPos->setEnabled(en);
517
ui->yPos->setEnabled(en);
518
ui->zPos->setEnabled(en);
521
void DlgRevolution::onSelectionChanged(const Gui::SelectionChanges& msg)
523
if (msg.Type == Gui::SelectionChanges::AddSelection) {
524
if (filter && filter->canSelect) {
525
this->setAxisLink(msg.pObjectName, msg.pSubName);
530
App::DocumentObject&DlgRevolution::getShapeToRevolve() const
532
std::vector<App::DocumentObject*> objs = this->getShapesToRevolve();
534
throw Base::ValueError("No shapes selected");
538
void DlgRevolution::autoSolid()
541
App::DocumentObject &dobj = this->getShapeToRevolve();
542
Part::TopoShape topoShape = Part::Feature::getTopoShape(&dobj);
543
if (topoShape.isNull()) {
546
TopoDS_Shape sh = topoShape.getShape();
549
ShapeExtend_Explorer xp;
550
Handle(TopTools_HSequenceOfShape) leaves = xp.SeqFromCompound(sh, Standard_True);
551
int cntClosedWires = 0;
552
for (int i = 0; i < leaves->Length(); i++) {
553
const TopoDS_Shape &leaf = leaves->Value(i+1);
556
if (leaf.ShapeType() == TopAbs_WIRE || leaf.ShapeType() == TopAbs_EDGE){
557
if (BRep_Tool::IsClosed(leaf)){
562
ui->checkSolid->setChecked( cntClosedWires == leaves->Length() );
572
TaskRevolution::TaskRevolution()
574
widget = new DlgRevolution();
575
addTaskBox(Gui::BitmapFactory().pixmap("Part_Revolve"), widget);
578
bool TaskRevolution::accept()
581
return (widget->result() == QDialog::Accepted);
584
#include "moc_DlgRevolution.cpp"